Skip to content

Commit

Permalink
docs: updates custom components and field props (#9157)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobsfletch authored Nov 12, 2024
1 parent 8c2fc71 commit 9ee6425
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 548 deletions.
6 changes: 3 additions & 3 deletions docs/admin/collections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ The following options are available:
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. A field with `virtual: true` cannot be used as the title. |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#components). |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#custom-components). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](./metadata). |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#components). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#custom-components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |

### Components
### Custom Components

Collections can set their own [Custom Components](./components) which only apply to [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.

Expand Down
242 changes: 122 additions & 120 deletions docs/admin/components.mdx

Large diffs are not rendered by default.

455 changes: 182 additions & 273 deletions docs/admin/fields.mdx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/admin/globals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ The following options are available:
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](#components). |
| **`components`** | Swap in your own React components to be used within this Global. [More details](#custom-components). |
| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Page metadata overrides to apply to this Global within the Admin Panel. [More details](./metadata). |

### Components
### Custom Components

Globals can set their own [Custom Components](./components) which only apply to [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.

Expand Down
49 changes: 1 addition & 48 deletions docs/admin/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The `useField` hook accepts the following arguments:

| Property | Description |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `path` | If you do not provide a `path` or a `name`, this hook will look for one using the [`useFieldProps`](#usefieldprops) hook. |
| `path` | If you do not provide a `path`, `name` will be used instead. This is the path to the field in the form data. |
| `validate` | A validation function executed client-side _before_ submitting the form to the server. Different than [Field-level Validation](../fields/overview#validation) which runs strictly on the server. |
| `disableFormData` | If `true`, the field will not be included in the form data when the form is submitted. |
| `hasRows` | If `true`, the field will be treated as a field with rows. This is useful for fields like `array` and `blocks`. |
Expand Down Expand Up @@ -72,32 +72,6 @@ type FieldType<T> = {
}
```
## useFieldProps
[Custom Field Components](./fields#the-field-component) can be rendered on the server. When using a server component as a custom field component, you can access dynamic props from within any client component rendered by your custom server component. This is done using the `useFieldProps` hook. This is important because some fields can be dynamic, such as when nested in an [`array`](../fields/array) or [`blocks`](../fields/block) field. For example, items can be added, re-ordered, or deleted on-the-fly.
You can use the `useFieldProps` hooks to access dynamic props like `path`:
```tsx
'use client'
import { useFieldProps } from '@payloadcms/ui'

const CustomTextField: React.FC = () => {
const { path } = useFieldProps() // highlight-line

return (
<div>
{path}
</div>
)
}
```

<Banner type="success">
<strong>Tip:</strong>
The [`useField`](#usefield) hook calls the `useFieldProps` hook internally, so you don't need to use both in the same component unless explicitly needed.
</Banner>

## useFormFields
There are times when a custom field component needs to have access to data from other fields, and you have a few options to do so. The `useFormFields` hook is a powerful and highly performant way to retrieve a form's field state, as well as to retrieve the `dispatchFields` method, which can be helpful for setting other fields' form states from anywhere within a form.
Expand Down Expand Up @@ -900,27 +874,6 @@ const MyComponent: React.FC = () => {
}
```

## useTableCell

Similar to [`useFieldProps`](#usefieldprops), all [Custom Cell Components](./fields#the-cell-component) are rendered on the server, and as such, only have access to static props at render time. But, some props need to be dynamic, such as the field value itself.

For this reason, dynamic props like `cellData` are managed in their own React context, which can be accessed using the `useTableCell` hook.

```tsx
'use client'
import { useTableCell } from '@payloadcms/ui'

const MyComponent: React.FC = () => {
const { cellData } = useTableCell() // highlight-line

return (
<div>
{cellData}
</div>
)
}
```

## useDocumentEvents

The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following:
Expand Down
2 changes: 1 addition & 1 deletion docs/fields/join.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ You can control the user experience of the join field using the `admin` config p
| Option | Description |
|------------------------|----------------------------------------------------------------------------------------|
| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. |
| **`components.Label`** | Override the default Label of the Field Component. [More details](#the-label-component). |
| **`components.Label`** | Override the default Label of the Field Component. [More details](../admin/fields#label) |

## Join Field Data

Expand Down
2 changes: 1 addition & 1 deletion docs/fields/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Here are the available Presentational Fields:

<Banner type="warning">
<strong>Tip:</strong>
Don't see a Field Type that fits your needs? You can build your own using a [Custom Field Component](../admin/fields#the-field-component).
Don't see a Field Type that fits your needs? You can build your own using a [Custom Field Component](../admin/fields#field).
</Banner>

## Field Options
Expand Down
2 changes: 1 addition & 1 deletion docs/fields/select.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,4 @@ If you are looking to create a dynamic select field, the following tutorial will
drawerTitle="How to Create a Custom Select Field: A Step-by-Step Guide"
/>

If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/components#field-component) docs.
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/components#field) docs.
4 changes: 2 additions & 2 deletions docs/fields/ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export const MyUIField: Field = {
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | A unique identifier for this field. |
| **`label`** | Human-readable label for this UI field. |
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit View. [More](../admin/components/#field-component) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/components/#field-component) |
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit View. [More](../admin/components/#field) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/components/#field) |
| **`admin.disableListColumn`** | Set `disableListColumn` to `true` to prevent the UI field from appearing in the list view column selector. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |

Expand Down
69 changes: 4 additions & 65 deletions docs/migration-guide/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ import {
useEntityVisibility,
useField,
useFieldComponents,
useFieldProps,
useForm,
useFormFields,
useFormInitializing,
Expand All @@ -199,7 +198,6 @@ import {
useSearchParams,
useSelection,
useStepNav,
useTableCell,
useTheme,
useThrottledEffect,
useTranslation,
Expand Down Expand Up @@ -468,10 +466,9 @@ export const ServerRenderedDescription = () => <ClientRenderedDescription />
'use client'
import React from 'react'
import type { TextFieldDescriptionClientComponent } from 'payload'
import { useFieldProps, useFormFields } from '@payloadcms/ui'
import { useFormFields } from '@payloadcms/ui'

export const ClientRenderedDescription: TextFieldDescriptionClientComponent = () ={
const { path } = useFieldProps()
export const ClientRenderedDescription: TextFieldDescriptionClientComponent = ({ path }) => {
const { value } = useFormFields(([fields]) => fields[path])
const customDescription = `Component description: ${path} - ${value}`

Expand Down Expand Up @@ -526,74 +523,16 @@ export const ServerRenderedCollapsibleLabel = () => <ClientCollapsibleLabel />
// file: components/ClientCollapsibleLabel.tsx
'use client'
import React from 'react'
import { useFieldProps, useFormFields } from '@payloadcms/ui'
import { useFormFields } from '@payloadcms/ui'

export const ClientCollapsibleLabel = () => {
const { path } = useFieldProps()
export const ClientCollapsibleLabel = ({ path }) => {
const { value } = useFormFields(([fields]) => fields[path])
const customLabel = `${value?.fieldInCollapsible || 'Untitled Collapsible'}`

return <div>{customLabel}</div>
}
```
11. The `admin.components.Cell` no longer receives `rowData` or `cellData`.
If using a custom component, you must now get the data yourself via the `useTableCell` hook, i.e. `const { cellData, rowData } = useTableCell()`.
```tsx
// file: payload.config.ts
import { buildConfig } from 'payload'
import { ServerRenderedTitleCell } from './components/ServerRenderedTitleCell.tsx'

export default buildConfig({
// ...
collections: [
{
slug: 'posts',
fields: [
{
name: 'title',
type: 'text',
admin: {
components: {
Cell: ServerRenderedTitleCell
}
}
}
]
}
]
// ...
})


// file: components/ServerRenderedTitleCell.tsx
import React from 'react'

import { ClientTitleCell } from './ClientTitleCell.tsx'

export const ServerRenderedTitleCell = () => <ClientTitleCell />


// file: components/ClientTitleCell.tsx
'use client'
import React from 'react'
import { useTableCell } from '@payloadcms/ui'

export const ClientTitleCell: CellComponent = () ={
const { cellData, rowData } = useTableCell()
const customCellText = `Component cell: ${cellData}`

return (
<div>
{customCellText}
</div>
)
}
```
12. `admin.components.RowLabel` no longer accepts a function, instead use a custom component and make use of the `useRowLabel` hook:
```tsx
Expand Down
4 changes: 1 addition & 3 deletions packages/payload/src/admin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import type { AcceptedLanguages, I18nClient } from '@payloadcms/translations'
import type React from 'react'

import type { ImportMap } from '../bin/generateImportMap/index.js'
import type { SanitizedCollectionConfig } from '../collections/config/types.js'
import type { SanitizedConfig } from '../config/types.js'
import type { Block, ClientField, Field, FieldTypes, Tab } from '../fields/config/types.js'
import type { SanitizedGlobalConfig } from '../globals/config/types.js'
import type { Block, Field, FieldTypes, Tab } from '../fields/config/types.js'
import type { JsonObject } from '../types/index.js'
import type {
BuildFormStateArgs,
Expand Down
20 changes: 8 additions & 12 deletions test/_community/collections/Posts/MyClientField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,13 @@ export const MyClientFieldComponent: TextFieldClientComponent = ({
schemaPath,
}) => {
return (
<>
<h1>HELLO</h1>
<p>{path}</p>
<TextField
field={field}
indexPath={indexPath}
parentPath={parentPath}
parentSchemaPath={parentSchemaPath}
path={path}
schemaPath={schemaPath}
/>
</>
<TextField
field={field}
indexPath={indexPath}
parentPath={parentPath}
parentSchemaPath={parentSchemaPath}
path={path}
schemaPath={schemaPath}
/>
)
}
30 changes: 13 additions & 17 deletions test/_community/collections/Posts/MyServerField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,27 @@ import type { TextFieldServerComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
import React from 'react'

export const MyServerFieldComponent: TextFieldServerComponent = (args) => {
export const MyServerFieldComponent: TextFieldServerComponent = (props) => {
const {
clientField,
indexPath,
parentPath,
parentSchemaPath,
path,
schemaPath,
siblingData,
value,
} = args
// siblingData,
// value,
// data
} = props

return (
<React.Fragment>
<h1>{String(value)}</h1>
<p>{JSON.stringify(siblingData)}</p>
<p>{path}</p>
<TextField
field={clientField}
indexPath={indexPath}
parentPath={parentPath}
parentSchemaPath={parentSchemaPath}
path={path}
schemaPath={schemaPath}
/>
</React.Fragment>
<TextField
field={clientField}
indexPath={indexPath}
parentPath={parentPath}
parentSchemaPath={parentSchemaPath}
path={path}
schemaPath={schemaPath}
/>
)
}

0 comments on commit 9ee6425

Please sign in to comment.