Compare commits
8 Commits
v3.0.0-bet
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
227d2e0502 | ||
|
|
3a91deb0a4 | ||
|
|
9e6e8357b8 | ||
|
|
0dd17e6347 | ||
|
|
17312d9f90 | ||
|
|
0c36cbde73 | ||
|
|
ebd43c7763 | ||
|
|
adf2f31178 |
14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
@@ -18,7 +18,7 @@ concurrency:
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.20.2
|
||||
PNPM_VERSION: 9.7.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
@@ -207,6 +207,9 @@ jobs:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 25
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
@@ -222,12 +225,7 @@ jobs:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
timeout-minutes: 10
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
- run: pnpm install
|
||||
|
||||
- name: Start LocalStack
|
||||
run: pnpm docker:start
|
||||
@@ -371,7 +369,7 @@ jobs:
|
||||
run: pnpm exec playwright install-deps chromium
|
||||
|
||||
- name: E2E Tests
|
||||
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e ${{ matrix.suite }}
|
||||
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci ${{ matrix.suite }}
|
||||
env:
|
||||
PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
|
||||
2
.github/workflows/release-canary.yml
vendored
2
.github/workflows/release-canary.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.20.2
|
||||
PNPM_VERSION: 9.7.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,7 +5,7 @@ dist
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/payload.iml
|
||||
|
||||
|
||||
test/packed
|
||||
test-results
|
||||
.devcontainer
|
||||
.localstack
|
||||
@@ -306,3 +306,6 @@ test/live-preview/app/(payload)/admin/importMap.js
|
||||
/test/live-preview/app/(payload)/admin/importMap.js
|
||||
test/admin-root/app/(payload)/admin/importMap.js
|
||||
/test/admin-root/app/(payload)/admin/importMap.js
|
||||
test/app/(payload)/admin/importMap.js
|
||||
/test/app/(payload)/admin/importMap.js
|
||||
test/pnpm-lock.yaml
|
||||
|
||||
@@ -36,7 +36,7 @@ The following options are available:
|
||||
| **`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`** | Metadata overrides to apply to the Admin Panel. Included properties are `description` and `openGraph`. |
|
||||
| **`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). |
|
||||
|
||||
@@ -347,31 +347,13 @@ Custom Label Components receive all [Field Component](#the-field-component) prop
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview). The convention is to append `LabelComponent` to the type of field, i.e. `TextFieldLabelComponent`.
|
||||
When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldLabelComponent,
|
||||
BlocksFieldLabelComponent,
|
||||
CheckboxFieldLabelComponent,
|
||||
CodeFieldLabelComponent,
|
||||
CollapsibleFieldLabelComponent,
|
||||
DateFieldLabelComponent,
|
||||
EmailFieldLabelComponent,
|
||||
GroupFieldLabelComponent,
|
||||
HiddenFieldLabelComponent,
|
||||
JSONFieldLabelComponent,
|
||||
NumberFieldLabelComponent,
|
||||
PointFieldLabelComponent,
|
||||
RadioFieldLabelComponent,
|
||||
RelationshipFieldLabelComponent,
|
||||
RichTextFieldLabelComponent,
|
||||
RowFieldLabelComponent,
|
||||
SelectFieldLabelComponent,
|
||||
TabsFieldLabelComponent,
|
||||
TextFieldLabelComponent,
|
||||
TextareaFieldLabelComponent,
|
||||
UploadFieldLabelComponent
|
||||
TextFieldLabelServerComponent,
|
||||
TextFieldLabelClientComponent,
|
||||
// And so on for each Field Type
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
@@ -410,31 +392,13 @@ Custom Error Components receive all [Field Component](#the-field-component) prop
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview). The convention is to append `ErrorComponent` to the type of field, i.e. `TextFieldErrorComponent`.
|
||||
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldErrorComponent,
|
||||
BlocksFieldErrorComponent,
|
||||
CheckboxFieldErrorComponent,
|
||||
CodeFieldErrorComponent,
|
||||
CollapsibleFieldErrorComponent,
|
||||
DateFieldErrorComponent,
|
||||
EmailFieldErrorComponent,
|
||||
GroupFieldErrorComponent,
|
||||
HiddenFieldErrorComponent,
|
||||
JSONFieldErrorComponent,
|
||||
NumberFieldErrorComponent,
|
||||
PointFieldErrorComponent,
|
||||
RadioFieldErrorComponent,
|
||||
RelationshipFieldErrorComponent,
|
||||
RichTextFieldErrorComponent,
|
||||
RowFieldErrorComponent,
|
||||
SelectFieldErrorComponent,
|
||||
TabsFieldErrorComponent,
|
||||
TextFieldErrorComponent,
|
||||
TextareaFieldErrorComponent,
|
||||
UploadFieldErrorComponent
|
||||
TextFieldErrorServerComponent,
|
||||
TextFieldErrorClientComponent,
|
||||
// And so on for each Field Type
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
@@ -544,31 +508,13 @@ Custom Description Components receive all [Field Component](#the-field-component
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview). The convention is to append `DescriptionComponent` to the type of field, i.e. `TextFieldDescriptionComponent`.
|
||||
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldDescriptionComponent,
|
||||
BlocksFieldDescriptionComponent,
|
||||
CheckboxFieldDescriptionComponent,
|
||||
CodeFieldDescriptionComponent,
|
||||
CollapsibleFieldDescriptionComponent,
|
||||
DateFieldDescriptionComponent,
|
||||
EmailFieldDescriptionComponent,
|
||||
GroupFieldDescriptionComponent,
|
||||
HiddenFieldDescriptionComponent,
|
||||
JSONFieldDescriptionComponent,
|
||||
NumberFieldDescriptionComponent,
|
||||
PointFieldDescriptionComponent,
|
||||
RadioFieldDescriptionComponent,
|
||||
RelationshipFieldDescriptionComponent,
|
||||
RichTextFieldDescriptionComponent,
|
||||
RowFieldDescriptionComponent,
|
||||
SelectFieldDescriptionComponent,
|
||||
TabsFieldDescriptionComponent,
|
||||
TextFieldDescriptionComponent,
|
||||
TextareaFieldDescriptionComponent,
|
||||
UploadFieldDescriptionComponent
|
||||
TextFieldDescriptionServerComponent,
|
||||
TextFieldDescriptionClientComponent,
|
||||
// And so on for each Field Type
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ The following options are available:
|
||||
| **`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`** | Metadata overrides to apply to the Admin Panel. Included properties are `description` and `openGraph`. |
|
||||
| **`meta`** | Page metadata overrides to apply to this Global within the Admin Panel. [More details](./metadata). |
|
||||
|
||||
### Components
|
||||
|
||||
|
||||
216
docs/admin/metadata.mdx
Normal file
216
docs/admin/metadata.mdx
Normal file
@@ -0,0 +1,216 @@
|
||||
---
|
||||
title: Page Metadata
|
||||
label: Metadata
|
||||
order: 70
|
||||
desc: Customize the metadata of your pages within the Admin Panel
|
||||
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Every page within the Admin Panel automatically receives dynamic, auto-generated metadata derived from live document data, the user's current locale, and more, without any additional configuration. This includes the page title, description, og:image and everything in between. Metadata is fully configurable at the root level and cascades down to individual collections, documents, and custom views, allowing for the ability to control metadata on any page with high precision.
|
||||
|
||||
Within the Admin Panel, metadata can be customized at the following levels:
|
||||
|
||||
- [Root Metadata](#root-metadata)
|
||||
- [Collection Metadata](#collection-metadata)
|
||||
- [Global Metadata](#global-metadata)
|
||||
- [View Metadata](#view-metadata)
|
||||
|
||||
All of these types of metadata share a similar structure, with a few key differences on the Root level. To customize metadata, consult the list of available scopes. Determine the scope that corresponds to what you are trying to accomplish, then author your metadata within the Payload Config accordingly.
|
||||
|
||||
## Root Metadata
|
||||
|
||||
Root Metadata is the metadata that is applied to all pages within the Admin Panel. This is where you can control things like the suffix appended onto each page's title, the favicon displayed in the browser's tab, and the Open Graph data that is used when sharing the Admin Panel on social media.
|
||||
|
||||
To customize Root Metadata, use the `admin.meta` key in your Payload Config:
|
||||
|
||||
```ts
|
||||
{
|
||||
// ...
|
||||
admin: {
|
||||
// highlight-start
|
||||
meta: {
|
||||
// highlight-end
|
||||
title: 'My Admin Panel',
|
||||
description: 'The best admin panel in the world',
|
||||
icons: [
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/png',
|
||||
href: '/favicon.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following options are available for Root Metadata:
|
||||
|
||||
| Key | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| **`title`** | `string` | The title of the Admin Panel. |
|
||||
| **`description`** | `string` | The description of the Admin Panel. |
|
||||
| **`defaultOGImageType`** | `dynamic` (default), `static`, or `off` | The type of default OG image to use. If set to `dynamic`, Payload will use Next.js image generation to create an image with the title of the page. If set to `static`, Payload will use the `defaultOGImage` URL. If set to `off`, Payload will not generate an OG image. |
|
||||
| **`icons`** | `IconConfig[]` | An array of icon objects. [More details](#icons) |
|
||||
| **`keywords`** | `string` | A comma-separated list of keywords to include in the metadata of the Admin Panel. |
|
||||
| **`openGraph`** | `OpenGraphConfig` | An object containing Open Graph metadata. [More details](#open-graph) |
|
||||
| **`titleSuffix`** | `string` | A suffix to append to the end of the title of every page. Defaults to "- Payload". |
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Metadata](./collections), [Global Metadata](./globals), and [Document Metadata](./documents) in their respective configs.
|
||||
</Banner>
|
||||
|
||||
### Icons
|
||||
|
||||
The Icons Config corresponds to the `<link>` tags that are used to specify icons for the Admin Panel. The `icons` key is an array of objects, each of which represents an individual icon. Icons are differentiated from one another by their `rel` attribute, which specifies the relationship between the document and the icon.
|
||||
|
||||
The most common icon type is the favicon, which is displayed in the browser tab. This is specified by the `rel` attribute `icon`. Other common icon types include `apple-touch-icon`, which is used by Apple devices when the Admin Panel is saved to the home screen, and `mask-icon`, which is used by Safari to mask the Admin Panel icon.
|
||||
|
||||
To customize icons, use the `icons` key within the `admin.meta` object in your Payload Config:
|
||||
|
||||
```ts
|
||||
{
|
||||
// ...
|
||||
admin: {
|
||||
meta: {
|
||||
// highlight-start
|
||||
icons: [
|
||||
// highlight-end
|
||||
{
|
||||
rel: 'icon',
|
||||
type: 'image/png',
|
||||
href: '/favicon.png',
|
||||
},
|
||||
{
|
||||
rel: 'apple-touch-icon',
|
||||
type: 'image/png',
|
||||
href: '/apple-touch-icon.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following options are available for Icons:
|
||||
|
||||
| Key | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| **`rel`** | `string` | The HTML `rel` attribute of the icon. |
|
||||
| **`type`** | `string` | The MIME type of the icon. |
|
||||
| **`color`** | `string` | The color of the icon. |
|
||||
| **`fetchPriority`** | `string` | The [fetch priority](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority) of the icon. |
|
||||
| **`media`** | `string` | The [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) of the icon. |
|
||||
| **`sizes`** | `string` | The [sizes](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes) of the icon. |
|
||||
| **`url`** | `string` | The URL pointing the resource of the icon. |
|
||||
|
||||
### Open Graph
|
||||
|
||||
Open Graph metadata is a set of tags that are used to control how URLs are displayed when shared on social media platforms. Open Graph metadata is automatically generated by Payload, but can be customized at the Root level.
|
||||
|
||||
To customize Open Graph metadata, use the `openGraph` key within the `admin.meta` object in your Payload Config:
|
||||
|
||||
```ts
|
||||
{
|
||||
// ...
|
||||
admin: {
|
||||
meta: {
|
||||
// highlight-start
|
||||
openGraph: {
|
||||
// highlight-end
|
||||
description: 'The best admin panel in the world',
|
||||
images: [
|
||||
{
|
||||
url: 'https://example.com/image.jpg',
|
||||
width: 800,
|
||||
height: 600,
|
||||
},
|
||||
],
|
||||
siteName: 'Payload',
|
||||
title: 'My Admin Panel',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following options are available for Open Graph Metadata:
|
||||
|
||||
| Key | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| **`description`** | `string` | The description of the Admin Panel. |
|
||||
| **`images`** | `OGImageConfig | OGImageConfig[]` | An array of image objects. |
|
||||
| **`siteName`** | `string` | The name of the site. |
|
||||
| **`title`** | `string` | The title of the Admin Panel. |
|
||||
|
||||
## Collection Metadata
|
||||
|
||||
Collection Metadata is the metadata that is applied to all pages within any given Collection within the Admin Panel. This metadata is used to customize the title and description of all views within any given Collection, unless overridden by the view itself.
|
||||
|
||||
To customize Collection Metadata, use the `admin.meta` key within your Collection Config:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const MyCollection: CollectionConfig = {
|
||||
// ...
|
||||
admin: {
|
||||
// highlight-start
|
||||
meta: {
|
||||
// highlight-end
|
||||
title: 'My Collection',
|
||||
description: 'The best collection in the world',
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The Collection Meta config has the same options as the [Root Metadata](#root-metadata) config.
|
||||
|
||||
## Global Metadata
|
||||
|
||||
Global Metadata is the metadata that is applied to all pages within any given Global within the Admin Panel. This metadata is used to customize the title and description of all views within any given Global, unless overridden by the view itself.
|
||||
|
||||
To customize Global Metadata, use the `admin.meta` key within your Global Config:
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload'
|
||||
|
||||
export const MyGlobal: GlobalConfig = {
|
||||
// ...
|
||||
admin: {
|
||||
// highlight-start
|
||||
meta: {
|
||||
// highlight-end
|
||||
title: 'My Global',
|
||||
description: 'The best
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The Global Meta config has the same options as the [Root Metadata](#root-metadata) config.
|
||||
|
||||
## View Metadata
|
||||
|
||||
View Metadata is the metadata that is applied to specific [Views](./views) within the Admin Panel. This metadata is used to customize the title and description of a specific view, overriding any metadata set at the [Root](#root-metadata), [Collection](#collection-metadata), or [Global](#global-metadata) level.
|
||||
|
||||
To customize View Metadata, use the `meta` key within your View Config:
|
||||
|
||||
```ts
|
||||
{
|
||||
// ...
|
||||
admin: {
|
||||
views: {
|
||||
dashboard: {
|
||||
// highlight-start
|
||||
meta: {
|
||||
// highlight-end
|
||||
title: 'My Dashboard',
|
||||
description: 'The best dashboard in the world',
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -88,17 +88,17 @@ The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
|
||||
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
|
||||
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
|
||||
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
|
||||
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
|
||||
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
|
||||
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
|
||||
| **`avatar`** | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| **`autoLogin`** | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
|
||||
| **`buildPath`** | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
|
||||
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
|
||||
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
|
||||
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| **`disable`** | If set to `true`, the entire Admin Panel will be disabled. |
|
||||
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| **`meta`** | Base metadata to use for the Admin Panel. [More details](./metadata). |
|
||||
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
|
||||
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
|
||||
@@ -57,7 +57,8 @@ For more granular control, pass a configuration object instead. Payload exposes
|
||||
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
|
||||
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
|
||||
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
|
||||
| **`sensitive`** | When true, will match if the path is case sensitive. |
|
||||
| **`sensitive`** | When true, will match if the path is case sensitive.
|
||||
| **`meta`** | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
|
||||
@@ -467,10 +467,10 @@ export const ServerRenderedDescription = () => <ClientRenderedDescription />
|
||||
// file: components/ClientRenderedDescription.tsx
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import type { DescriptionComponent } from 'payload'
|
||||
import type { TextFieldDescriptionClientComponent } from 'payload'
|
||||
import { useFieldProps, useFormFields } from '@payloadcms/ui'
|
||||
|
||||
export const ClientRenderedDescription: DescriptionComponent = () ={
|
||||
export const ClientRenderedDescription: TextFieldDescriptionClientComponent = () ={
|
||||
const { path } = useFieldProps()
|
||||
const { value } = useFormFields(([fields]) => fields[path])
|
||||
const customDescription = `Component description: ${path} - ${value}`
|
||||
@@ -659,8 +659,8 @@ export const ClientArrayRowLabel = () => {
|
||||
admin: {
|
||||
components: {
|
||||
views: {
|
||||
Edit: {
|
||||
Tab: {
|
||||
edit: {
|
||||
tab: {
|
||||
pillLabel: '',
|
||||
},
|
||||
},
|
||||
@@ -675,9 +675,11 @@ export const ClientArrayRowLabel = () => {
|
||||
admin: {
|
||||
components: {
|
||||
views: {
|
||||
Edit: {
|
||||
Tab: {
|
||||
Pill: MyPill,
|
||||
edit: {
|
||||
tab: {
|
||||
pill: {
|
||||
Component: './path/to/CustomPill.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -53,7 +53,7 @@
|
||||
"clean:all": "node ./scripts/delete-recursively.js '@node_modules' 'media/*' '**/dist/' '**/.cache/*' '**/.next/*' '**/.turbo/*' '**/tsconfig.tsbuildinfo' '**/payload*.tgz' '**/meta_*.json'",
|
||||
"clean:build": "node ./scripts/delete-recursively.js 'media/' '**/dist/' '**/.cache/' '**/.next/' '**/.turbo/' '**/tsconfig.tsbuildinfo' '**/payload*.tgz' '**/meta_*.json'",
|
||||
"clean:cache": "node ./scripts/delete-recursively.js node_modules/.cache! packages/payload/node_modules/.cache! .next/*",
|
||||
"dev": "pnpm runts ./test/dev.ts",
|
||||
"dev": "tsx ./test/dev.ts",
|
||||
"dev:generate-graphql-schema": "pnpm runts ./test/generateGraphQLSchema.ts",
|
||||
"dev:generate-importmap": "pnpm runts ./test/generateImportMap.ts",
|
||||
"dev:generate-types": "pnpm runts ./test/generateTypes.ts",
|
||||
@@ -81,6 +81,8 @@
|
||||
"test:e2e": "pnpm runts ./test/runE2E.ts",
|
||||
"test:e2e:debug": "cross-env NODE_OPTIONS=--no-deprecation NODE_NO_WARNINGS=1 PWDEBUG=1 DISABLE_LOGGING=true playwright test",
|
||||
"test:e2e:headed": "cross-env NODE_OPTIONS=--no-deprecation NODE_NO_WARNINGS=1 DISABLE_LOGGING=true playwright test --headed",
|
||||
"test:e2e:prod": "pnpm bf && rm -rf test/packed && 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: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:unit": "cross-env NODE_OPTIONS=\"--no-deprecation\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=jest.config.js --runInBand",
|
||||
@@ -162,7 +164,6 @@
|
||||
"react": "^19.0.0 || ^19.0.0-rc-06d0b89e-20240801",
|
||||
"react-dom": "^19.0.0 || ^19.0.0-rc-06d0b89e-20240801"
|
||||
},
|
||||
"packageManager": "pnpm@9.7.0",
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0",
|
||||
"pnpm": "^9.7.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -53,8 +53,6 @@ import type { Args, PostgresAdapter } from './types.js'
|
||||
|
||||
import { connect } from './connect.js'
|
||||
|
||||
export { sql } from 'drizzle-orm'
|
||||
|
||||
export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter> {
|
||||
const postgresIDType = args.idType || 'serial'
|
||||
const payloadIDType = postgresIDType === 'serial' ? 'number' : 'text'
|
||||
@@ -159,3 +157,6 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
|
||||
init: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
export type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/drizzle/postgres'
|
||||
export { sql } from 'drizzle-orm'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-sqlite",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The officially supported SQLite database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/drizzle",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "A library of shared functions used by different payload database adapters",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official React SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-vue",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official Vue SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -7,7 +7,6 @@ import type {
|
||||
} from 'payload'
|
||||
|
||||
import { RenderComponent, getCreateMappedComponent } from '@payloadcms/ui/shared'
|
||||
import { isPlainObject } from 'payload'
|
||||
import React from 'react'
|
||||
|
||||
import { ShouldRenderTabs } from './ShouldRenderTabs.js'
|
||||
|
||||
@@ -14,7 +14,11 @@ if (!cached) {
|
||||
cached = global._payload = { payload: null, promise: null, reload: false, ws: null }
|
||||
}
|
||||
|
||||
export const reload = async (config: SanitizedConfig, payload: Payload): Promise<void> => {
|
||||
export const reload = async (
|
||||
config: SanitizedConfig,
|
||||
payload: Payload,
|
||||
skipImportMapGeneration?: boolean,
|
||||
): Promise<void> => {
|
||||
if (typeof payload.db.destroy === 'function') {
|
||||
await payload.db.destroy()
|
||||
}
|
||||
@@ -46,7 +50,7 @@ export const reload = async (config: SanitizedConfig, payload: Payload): Promise
|
||||
}
|
||||
|
||||
// Generate component map
|
||||
if (config.admin?.importMap?.autoGenerate !== false) {
|
||||
if (skipImportMapGeneration !== true && config.admin?.importMap?.autoGenerate !== false) {
|
||||
await generateImportMap(config, {
|
||||
log: true,
|
||||
})
|
||||
@@ -87,6 +91,7 @@ export const getPayloadHMR = async (options: InitOptions): Promise<Payload> => {
|
||||
return cached.payload
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
if (!cached.promise) {
|
||||
// no need to await options.config here, as it's already awaited in the BasePayload.init
|
||||
cached.promise = new BasePayload().init(options)
|
||||
|
||||
@@ -11,9 +11,9 @@ import './index.scss'
|
||||
const baseClass = 'payload-settings'
|
||||
|
||||
export const Settings: React.FC<{
|
||||
className?: string
|
||||
i18n: I18n
|
||||
languageOptions: LanguageOptions
|
||||
readonly className?: string
|
||||
readonly i18n: I18n
|
||||
readonly languageOptions: LanguageOptions
|
||||
}> = (props) => {
|
||||
const { className, i18n, languageOptions } = props
|
||||
|
||||
@@ -21,7 +21,7 @@ export const Settings: React.FC<{
|
||||
<div className={[baseClass, className].filter(Boolean).join(' ')}>
|
||||
<h3>{i18n.t('general:payloadSettings')}</h3>
|
||||
<div className={`${baseClass}__language`}>
|
||||
<FieldLabel htmlFor="language-select" label={i18n.t('general:language')} />
|
||||
<FieldLabel field={null} htmlFor="language-select" label={i18n.t('general:language')} />
|
||||
<LanguageSelector languageOptions={languageOptions} />
|
||||
</div>
|
||||
<ToggleTheme />
|
||||
|
||||
@@ -128,8 +128,6 @@ export const getViewsFromConfig = ({
|
||||
views,
|
||||
})
|
||||
|
||||
console.log('CustomViewComponent', customViewKey)
|
||||
|
||||
if (customViewKey) {
|
||||
viewKey = customViewKey
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ export const APIKey: React.FC<{ readonly enabled: boolean; readonly readOnly?: b
|
||||
Component: null,
|
||||
RenderedComponent: APIKeyLabel,
|
||||
}}
|
||||
field={null}
|
||||
htmlFor={path}
|
||||
/>
|
||||
<input
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { ArrayFieldClient } from '../../fields/config/types.js'
|
||||
import type { ArrayField, ArrayFieldClient } from '../../fields/config/types.js'
|
||||
import type { ArrayFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
DescriptionComponent,
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
LabelComponent,
|
||||
MappedComponent,
|
||||
} from '../types.js'
|
||||
|
||||
type ArrayFieldClientWithoutType = MarkOptional<ArrayFieldClient, 'type'>
|
||||
|
||||
export type ArrayFieldProps = {
|
||||
readonly CustomRowLabel?: MappedComponent
|
||||
readonly field: MarkOptional<ArrayFieldClient, 'type'>
|
||||
readonly validate?: ArrayFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<ArrayFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type ArrayFieldLabelComponent = LabelComponent<'array'>
|
||||
export type ArrayFieldLabelServerComponent = FieldLabelServerComponent<ArrayField>
|
||||
|
||||
export type ArrayFieldDescriptionComponent = DescriptionComponent<'array'>
|
||||
export type ArrayFieldLabelClientComponent = FieldLabelClientComponent<ArrayFieldClientWithoutType>
|
||||
|
||||
export type ArrayFieldErrorComponent = ErrorComponent<'array'>
|
||||
export type ArrayFieldDescriptionServerComponent = FieldDescriptionServerComponent<ArrayField>
|
||||
|
||||
export type ArrayFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<ArrayFieldClientWithoutType>
|
||||
|
||||
export type ArrayFieldErrorServerComponent = FieldErrorServerComponent<ArrayField>
|
||||
|
||||
export type ArrayFieldErrorClientComponent = FieldErrorClientComponent<ArrayFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { BlockFieldClient } from '../../fields/config/types.js'
|
||||
import type { BlockField, BlockFieldClient } from '../../fields/config/types.js'
|
||||
import type { BlockFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type BlocksFieldClientWithoutType = MarkOptional<BlockFieldClient, 'type'>
|
||||
|
||||
export type BlockFieldProps = {
|
||||
readonly field: MarkOptional<BlockFieldClient, 'type'>
|
||||
readonly validate?: BlockFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<BlocksFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type BlockFieldLabelComponent = LabelComponent<'blocks'>
|
||||
export type BlockFieldLabelServerComponent = FieldLabelServerComponent<BlockField>
|
||||
|
||||
export type BlockFieldDescriptionComponent = DescriptionComponent<'blocks'>
|
||||
export type BlockFieldLabelClientComponent = FieldLabelClientComponent<BlocksFieldClientWithoutType>
|
||||
|
||||
export type BlockFieldErrorComponent = ErrorComponent<'blocks'>
|
||||
export type BlockFieldDescriptionServerComponent = FieldDescriptionServerComponent<BlockField>
|
||||
|
||||
export type BlockFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<BlocksFieldClientWithoutType>
|
||||
|
||||
export type BlockFieldErrorServerComponent = FieldErrorServerComponent<BlockField>
|
||||
|
||||
export type BlockFieldErrorClientComponent = FieldErrorClientComponent<BlocksFieldClientWithoutType>
|
||||
|
||||
@@ -1,22 +1,38 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { CheckboxFieldClient } from '../../fields/config/types.js'
|
||||
import type { CheckboxField, CheckboxFieldClient } from '../../fields/config/types.js'
|
||||
import type { CheckboxFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type CheckboxFieldClientWithoutType = MarkOptional<CheckboxFieldClient, 'type'>
|
||||
|
||||
export type CheckboxFieldProps = {
|
||||
readonly checked?: boolean
|
||||
readonly disableFormData?: boolean
|
||||
readonly field: MarkOptional<CheckboxFieldClient, 'type'>
|
||||
readonly id?: string
|
||||
readonly onChange?: (value: boolean) => void
|
||||
readonly partialChecked?: boolean
|
||||
readonly validate?: CheckboxFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<CheckboxFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type CheckboxFieldLabelComponent = LabelComponent<'checkbox'>
|
||||
export type CheckboxFieldLabelServerComponent = FieldLabelServerComponent<CheckboxField>
|
||||
|
||||
export type CheckboxFieldDescriptionComponent = DescriptionComponent<'checkbox'>
|
||||
export type CheckboxFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<CheckboxFieldClientWithoutType>
|
||||
|
||||
export type CheckboxFieldErrorComponent = ErrorComponent<'checkbox'>
|
||||
export type CheckboxFieldDescriptionServerComponent = FieldDescriptionServerComponent<CheckboxField>
|
||||
|
||||
export type CheckboxFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<CheckboxFieldClientWithoutType>
|
||||
|
||||
export type CheckboxFieldErrorServerComponent = FieldErrorServerComponent<CheckboxField>
|
||||
|
||||
export type CheckboxFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<CheckboxFieldClientWithoutType>
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { CodeFieldClient } from '../../fields/config/types.js'
|
||||
import type { CodeField, CodeFieldClient } from '../../fields/config/types.js'
|
||||
import type { CodeFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type CodeFieldClientWithoutType = MarkOptional<CodeFieldClient, 'type'>
|
||||
|
||||
export type CodeFieldProps = {
|
||||
readonly autoComplete?: string
|
||||
readonly field: MarkOptional<CodeFieldClient, 'type'>
|
||||
readonly validate?: CodeFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<CodeFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type CodeFieldLabelComponent = LabelComponent<'code'>
|
||||
export type CodeFieldLabelServerComponent = FieldLabelServerComponent<CodeField>
|
||||
|
||||
export type CodeFieldDescriptionComponent = DescriptionComponent<'code'>
|
||||
export type CodeFieldLabelClientComponent = FieldLabelClientComponent<CodeFieldClientWithoutType>
|
||||
|
||||
export type CodeFieldErrorComponent = ErrorComponent<'code'>
|
||||
export type CodeFieldDescriptionServerComponent = FieldDescriptionServerComponent<CodeField>
|
||||
|
||||
export type CodeFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<CodeFieldClientWithoutType>
|
||||
|
||||
export type CodeFieldErrorServerComponent = FieldErrorServerComponent<CodeField>
|
||||
|
||||
export type CodeFieldErrorClientComponent = FieldErrorClientComponent<CodeFieldClientWithoutType>
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { CollapsibleFieldClient } from '../../fields/config/types.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { CollapsibleField, CollapsibleFieldClient } from '../../fields/config/types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
export type CollapsibleFieldProps = {
|
||||
readonly field: MarkOptional<CollapsibleFieldClient, 'type'>
|
||||
} & FormFieldBase
|
||||
type CollapsibleFieldClientWithoutType = MarkOptional<CollapsibleFieldClient, 'type'>
|
||||
|
||||
export type CollapsibleFieldLabelComponent = LabelComponent<'collapsible'>
|
||||
export type CollapsibleFieldProps = FormFieldBase<CollapsibleFieldClientWithoutType>
|
||||
|
||||
export type CollapsibleFieldDescriptionComponent = DescriptionComponent<'collapsible'>
|
||||
export type CollapsibleFieldLabelServerComponent = FieldLabelServerComponent<CollapsibleField>
|
||||
|
||||
export type CollapsibleFieldErrorComponent = ErrorComponent<'collapsible'>
|
||||
export type CollapsibleFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<CollapsibleFieldClientWithoutType>
|
||||
|
||||
export type CollapsibleFieldDescriptionServerComponent =
|
||||
FieldDescriptionServerComponent<CollapsibleField>
|
||||
|
||||
export type CollapsibleFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<CollapsibleFieldClientWithoutType>
|
||||
|
||||
export type CollapsibleFieldErrorServerComponent = FieldErrorServerComponent<CollapsibleField>
|
||||
|
||||
export type CollapsibleFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<CollapsibleFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { DateFieldClient } from '../../fields/config/types.js'
|
||||
import type { DateField, DateFieldClient } from '../../fields/config/types.js'
|
||||
import type { DateFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type DateFieldClientWithoutType = MarkOptional<DateFieldClient, 'type'>
|
||||
|
||||
export type DateFieldProps = {
|
||||
readonly field: MarkOptional<DateFieldClient, 'type'>
|
||||
readonly validate?: DateFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<DateFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type DateFieldLabelComponent = LabelComponent<'date'>
|
||||
export type DateFieldLabelServerComponent = FieldLabelServerComponent<DateField>
|
||||
|
||||
export type DateFieldDescriptionComponent = DescriptionComponent<'date'>
|
||||
export type DateFieldLabelClientComponent = FieldLabelClientComponent<DateFieldClientWithoutType>
|
||||
|
||||
export type DateFieldErrorComponent = ErrorComponent<'date'>
|
||||
export type DateFieldDescriptionServerComponent = FieldDescriptionServerComponent<DateField>
|
||||
|
||||
export type DateFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<DateFieldClientWithoutType>
|
||||
|
||||
export type DateFieldErrorServerComponent = FieldErrorServerComponent<DateField>
|
||||
|
||||
export type DateFieldErrorClientComponent = FieldErrorClientComponent<DateFieldClientWithoutType>
|
||||
|
||||
@@ -1,18 +1,32 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { EmailFieldClient } from '../../fields/config/types.js'
|
||||
import type { EmailField, EmailFieldClient } from '../../fields/config/types.js'
|
||||
import type { EmailFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type EmailFieldClientWithoutType = MarkOptional<EmailFieldClient, 'type'>
|
||||
|
||||
export type EmailFieldProps = {
|
||||
readonly autoComplete?: string
|
||||
readonly field: MarkOptional<EmailFieldClient, 'type'>
|
||||
readonly validate?: EmailFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<EmailFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type EmailFieldLabelComponent = LabelComponent<'email'>
|
||||
export type EmailFieldLabelServerComponent = FieldLabelServerComponent<EmailField>
|
||||
|
||||
export type EmailFieldDescriptionComponent = DescriptionComponent<'email'>
|
||||
export type EmailFieldLabelClientComponent = FieldLabelClientComponent<EmailFieldClientWithoutType>
|
||||
|
||||
export type EmailFieldErrorComponent = ErrorComponent<'email'>
|
||||
export type EmailFieldDescriptionServerComponent = FieldDescriptionServerComponent<EmailField>
|
||||
|
||||
export type EmailFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<EmailFieldClientWithoutType>
|
||||
|
||||
export type EmailFieldErrorServerComponent = FieldErrorServerComponent<EmailField>
|
||||
|
||||
export type EmailFieldErrorClientComponent = FieldErrorClientComponent<EmailFieldClientWithoutType>
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { GroupFieldClient } from '../../fields/config/types.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { GroupField, GroupFieldClient } from '../../fields/config/types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
export type GroupFieldProps = {
|
||||
readonly field: MarkOptional<GroupFieldClient, 'type'>
|
||||
} & FormFieldBase
|
||||
type GroupFieldClientWithoutType = MarkOptional<GroupFieldClient, 'type'>
|
||||
|
||||
export type GroupFieldLabelComponent = LabelComponent<'group'>
|
||||
export type GroupFieldProps = FormFieldBase<GroupFieldClientWithoutType>
|
||||
|
||||
export type GroupFieldDescriptionComponent = DescriptionComponent<'group'>
|
||||
export type GroupFieldLabelServerComponent = FieldLabelServerComponent<GroupField>
|
||||
|
||||
export type GroupFieldErrorComponent = ErrorComponent<'group'>
|
||||
export type GroupFieldLabelClientComponent = FieldLabelClientComponent<GroupFieldClientWithoutType>
|
||||
|
||||
export type GroupFieldDescriptionServerComponent = FieldDescriptionServerComponent<GroupField>
|
||||
|
||||
export type GroupFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<GroupFieldClientWithoutType>
|
||||
|
||||
export type GroupFieldErrorServerComponent = FieldErrorServerComponent<GroupField>
|
||||
|
||||
export type GroupFieldErrorClientComponent = FieldErrorClientComponent<GroupFieldClientWithoutType>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { ClientField } from '../../fields/config/client.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FormFieldBase } from '../types.js'
|
||||
|
||||
export type HiddenFieldProps = {
|
||||
readonly disableModifyingForm?: false
|
||||
@@ -10,9 +9,3 @@ export type HiddenFieldProps = {
|
||||
readonly forceUsePathFromProps?: boolean
|
||||
readonly value?: unknown
|
||||
} & FormFieldBase
|
||||
|
||||
export type HiddenFieldLabelComponent = LabelComponent<'hidden'>
|
||||
|
||||
export type HiddenFieldDescriptionComponent = DescriptionComponent<'hidden'>
|
||||
|
||||
export type HiddenFieldErrorComponent = ErrorComponent<'hidden'>
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { JSONFieldClient } from '../../fields/config/types.js'
|
||||
import type { JSONField, JSONFieldClient } from '../../fields/config/types.js'
|
||||
import type { JSONFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type JSONFieldClientWithoutType = MarkOptional<JSONFieldClient, 'type'>
|
||||
|
||||
export type JSONFieldProps = {
|
||||
readonly field: MarkOptional<JSONFieldClient, 'type'>
|
||||
readonly validate?: JSONFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<JSONFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type JSONFieldLabelComponent = LabelComponent<'json'>
|
||||
export type JSONFieldLabelServerComponent = FieldLabelServerComponent<JSONField>
|
||||
|
||||
export type JSONFieldDescriptionComponent = DescriptionComponent<'json'>
|
||||
export type JSONFieldLabelClientComponent = FieldLabelClientComponent<JSONFieldClientWithoutType>
|
||||
|
||||
export type JSONFieldErrorComponent = ErrorComponent<'json'>
|
||||
export type JSONFieldDescriptionServerComponent = FieldDescriptionServerComponent<JSONField>
|
||||
|
||||
export type JSONFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<JSONFieldClientWithoutType>
|
||||
|
||||
export type JSONFieldErrorServerComponent = FieldErrorServerComponent<JSONField>
|
||||
|
||||
export type JSONFieldErrorClientComponent = FieldErrorClientComponent<JSONFieldClientWithoutType>
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { NumberFieldClient } from '../../fields/config/types.js'
|
||||
import type { NumberField, NumberFieldClient } from '../../fields/config/types.js'
|
||||
import type { NumberFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type NumberFieldClientWithoutType = MarkOptional<NumberFieldClient, 'type'>
|
||||
|
||||
export type NumberFieldProps = {
|
||||
readonly field: MarkOptional<NumberFieldClient, 'type'>
|
||||
readonly onChange?: (e: number) => void
|
||||
readonly validate?: NumberFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<NumberFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type NumberFieldLabelComponent = LabelComponent<'number'>
|
||||
export type NumberFieldLabelServerComponent = FieldLabelServerComponent<NumberField>
|
||||
|
||||
export type NumberFieldDescriptionComponent = DescriptionComponent<'number'>
|
||||
export type NumberFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<NumberFieldClientWithoutType>
|
||||
|
||||
export type NumberFieldErrorComponent = ErrorComponent<'number'>
|
||||
export type NumberFieldDescriptionServerComponent = FieldDescriptionServerComponent<NumberField>
|
||||
|
||||
export type NumberFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<NumberFieldClientWithoutType>
|
||||
|
||||
export type NumberFieldErrorServerComponent = FieldErrorServerComponent<NumberField>
|
||||
|
||||
export type NumberFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<NumberFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { PointFieldClient } from '../../fields/config/types.js'
|
||||
import type { PointField, PointFieldClient } from '../../fields/config/types.js'
|
||||
import type { PointFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type PointFieldClientWithoutType = MarkOptional<PointFieldClient, 'type'>
|
||||
|
||||
export type PointFieldProps = {
|
||||
readonly field: MarkOptional<PointFieldClient, 'type'>
|
||||
readonly validate?: PointFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<PointFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type PointFieldLabelComponent = LabelComponent<'point'>
|
||||
export type PointFieldLabelServerComponent = FieldLabelServerComponent<PointField>
|
||||
|
||||
export type PointFieldDescriptionComponent = DescriptionComponent<'point'>
|
||||
export type PointFieldLabelClientComponent = FieldLabelClientComponent<PointFieldClientWithoutType>
|
||||
|
||||
export type PointFieldErrorComponent = ErrorComponent<'point'>
|
||||
export type PointFieldDescriptionServerComponent = FieldDescriptionServerComponent<PointField>
|
||||
|
||||
export type PointFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<PointFieldClientWithoutType>
|
||||
|
||||
export type PointFieldErrorServerComponent = FieldErrorServerComponent<PointField>
|
||||
|
||||
export type PointFieldErrorClientComponent = FieldErrorClientComponent<PointFieldClientWithoutType>
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { RadioFieldClient } from '../../fields/config/types.js'
|
||||
import type { RadioField, RadioFieldClient } from '../../fields/config/types.js'
|
||||
import type { RadioFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type RadioFieldClientWithoutType = MarkOptional<RadioFieldClient, 'type'>
|
||||
|
||||
export type RadioFieldProps = {
|
||||
readonly field: MarkOptional<RadioFieldClient, 'type'>
|
||||
readonly onChange?: OnChange
|
||||
readonly validate?: RadioFieldValidation
|
||||
readonly value?: string
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<RadioFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type OnChange<T = string> = (value: T) => void
|
||||
|
||||
export type RadioFieldLabelComponent = LabelComponent<'radio'>
|
||||
export type RadioFieldLabelServerComponent = FieldLabelServerComponent<RadioField>
|
||||
|
||||
export type RadioFieldDescriptionComponent = DescriptionComponent<'radio'>
|
||||
export type RadioFieldLabelClientComponent = FieldLabelClientComponent<RadioFieldClientWithoutType>
|
||||
|
||||
export type RadioFieldErrorComponent = ErrorComponent<'radio'>
|
||||
export type RadioFieldDescriptionServerComponent = FieldDescriptionServerComponent<RadioField>
|
||||
|
||||
export type RadioFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<RadioFieldClientWithoutType>
|
||||
|
||||
export type RadioFieldErrorServerComponent = FieldErrorServerComponent<RadioField>
|
||||
|
||||
export type RadioFieldErrorClientComponent = FieldErrorClientComponent<RadioFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { RelationshipFieldClient } from '../../fields/config/types.js'
|
||||
import type { RelationshipField, RelationshipFieldClient } from '../../fields/config/types.js'
|
||||
import type { RelationshipFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type RelationshipFieldClientWithoutType = MarkOptional<RelationshipFieldClient, 'type'>
|
||||
|
||||
export type RelationshipFieldProps = {
|
||||
readonly field: MarkOptional<RelationshipFieldClient, 'type'>
|
||||
readonly validate?: RelationshipFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<RelationshipFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type RelationshipFieldLabelComponent = LabelComponent<'relationship'>
|
||||
export type RelationshipFieldLabelServerComponent = FieldLabelServerComponent<RelationshipField>
|
||||
|
||||
export type RelationshipFieldDescriptionComponent = DescriptionComponent<'relationship'>
|
||||
export type RelationshipFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<RelationshipFieldClientWithoutType>
|
||||
|
||||
export type RelationshipFieldErrorComponent = ErrorComponent<'relationship'>
|
||||
export type RelationshipFieldDescriptionServerComponent =
|
||||
FieldDescriptionServerComponent<RelationshipField>
|
||||
|
||||
export type RelationshipFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<RelationshipFieldClientWithoutType>
|
||||
|
||||
export type RelationshipFieldErrorServerComponent = FieldErrorServerComponent<RelationshipField>
|
||||
|
||||
export type RelationshipFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<RelationshipFieldClientWithoutType>
|
||||
|
||||
@@ -1,21 +1,37 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { RichTextFieldClient } from '../../fields/config/types.js'
|
||||
import type { RichTextField, RichTextFieldClient } from '../../fields/config/types.js'
|
||||
import type { RichTextFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type RichTextFieldClientWithoutType = MarkOptional<RichTextFieldClient, 'type'>
|
||||
|
||||
export type RichTextFieldProps<
|
||||
TValue extends object = any,
|
||||
TAdapterProps = any,
|
||||
TExtraProperties = object,
|
||||
> = {
|
||||
readonly field: MarkOptional<RichTextFieldClient<TValue, TAdapterProps, TExtraProperties>, 'type'>
|
||||
readonly validate?: RichTextFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<RichTextFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type RichTextFieldLabelComponent = LabelComponent<'richText'>
|
||||
export type RichTextFieldLabelServerComponent = FieldLabelServerComponent<RichTextField>
|
||||
|
||||
export type RichTextFieldDescriptionComponent = DescriptionComponent<'richText'>
|
||||
export type RichTextFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<RichTextFieldClientWithoutType>
|
||||
|
||||
export type RichTextFieldErrorComponent = ErrorComponent<'richText'>
|
||||
export type RichTextFieldDescriptionServerComponent = FieldDescriptionServerComponent<RichTextField>
|
||||
|
||||
export type RichTextFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<RichTextFieldClientWithoutType>
|
||||
|
||||
export type RichTextFieldErrorServerComponent = FieldErrorServerComponent<RichTextField>
|
||||
|
||||
export type RichTextFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<RichTextFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,32 @@
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from 'payload'
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { RowFieldClient } from '../../fields/config/types.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { RowField, RowFieldClient } from '../../fields/config/types.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldErrorClientComponent,
|
||||
FieldErrorServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type RowFieldClientWithoutType = MarkOptional<RowFieldClient, 'type'>
|
||||
|
||||
export type RowFieldProps = {
|
||||
field: MarkOptional<RowFieldClient, 'type'>
|
||||
forceRender?: boolean
|
||||
indexPath: string
|
||||
} & FormFieldBase
|
||||
readonly forceRender?: boolean
|
||||
readonly indexPath: string
|
||||
} & FormFieldBase<RowFieldClientWithoutType>
|
||||
|
||||
export type RowFieldLabelComponent = LabelComponent<'row'>
|
||||
export type RowFieldLabelServerComponent = FieldLabelServerComponent<RowField>
|
||||
|
||||
export type RowFieldDescriptionComponent = DescriptionComponent<'row'>
|
||||
export type RowFieldLabelClientComponent = FieldLabelClientComponent<RowFieldClientWithoutType>
|
||||
|
||||
export type RowFieldErrorComponent = ErrorComponent<'row'>
|
||||
export type RowFieldDescriptionServerComponent = FieldDescriptionServerComponent<RowField>
|
||||
|
||||
export type RowFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<RowFieldClientWithoutType>
|
||||
|
||||
export type RowFieldErrorServerComponent = FieldErrorServerComponent<RowField>
|
||||
|
||||
export type RowFieldErrorClientComponent = FieldErrorClientComponent<RowFieldClientWithoutType>
|
||||
|
||||
@@ -1,19 +1,35 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { SelectFieldClient } from '../../fields/config/types.js'
|
||||
import type { SelectField, SelectFieldClient } from '../../fields/config/types.js'
|
||||
import type { SelectFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type SelectFieldClientWithoutType = MarkOptional<SelectFieldClient, 'type'>
|
||||
|
||||
export type SelectFieldProps = {
|
||||
readonly field: MarkOptional<SelectFieldClient, 'type'>
|
||||
readonly onChange?: (e: string | string[]) => void
|
||||
readonly validate?: SelectFieldValidation
|
||||
readonly value?: string
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<SelectFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type SelectFieldLabelComponent = LabelComponent<'select'>
|
||||
export type SelectFieldLabelServerComponent = FieldLabelServerComponent<SelectField>
|
||||
|
||||
export type SelectFieldDescriptionComponent = DescriptionComponent<'select'>
|
||||
export type SelectFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<SelectFieldClientWithoutType>
|
||||
|
||||
export type SelectFieldErrorComponent = ErrorComponent<'select'>
|
||||
export type SelectFieldDescriptionServerComponent = FieldDescriptionServerComponent<SelectField>
|
||||
|
||||
export type SelectFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<SelectFieldClientWithoutType>
|
||||
|
||||
export type SelectFieldErrorServerComponent = FieldErrorServerComponent<SelectField>
|
||||
|
||||
export type SelectFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<SelectFieldClientWithoutType>
|
||||
|
||||
@@ -3,22 +3,36 @@ import type { MarkOptional } from 'ts-essentials'
|
||||
import type {
|
||||
ClientField,
|
||||
NamedTab,
|
||||
TabsField,
|
||||
TabsFieldClient,
|
||||
UnnamedTab,
|
||||
} from '../../fields/config/types.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
export type ClientTab =
|
||||
| ({ fields: ClientField[] } & Omit<NamedTab, 'fields'>)
|
||||
| ({ fields: ClientField[] } & Omit<UnnamedTab, 'fields'>)
|
||||
|
||||
export type TabsFieldProps = {
|
||||
readonly field: MarkOptional<TabsFieldClient, 'type'>
|
||||
} & FormFieldBase
|
||||
export type TabsFieldClientWithoutType = MarkOptional<TabsFieldClient, 'type'>
|
||||
|
||||
export type TabsFieldLabelComponent = LabelComponent<'tabs'>
|
||||
export type TabsFieldProps = FormFieldBase<TabsFieldClientWithoutType>
|
||||
|
||||
export type TabsFieldDescriptionComponent = DescriptionComponent<'tabs'>
|
||||
export type TabsFieldLabelServerComponent = FieldLabelServerComponent<TabsField>
|
||||
|
||||
export type TabsFieldErrorComponent = ErrorComponent<'tabs'>
|
||||
export type TabsFieldLabelClientComponent = FieldLabelClientComponent<TabsFieldClientWithoutType>
|
||||
|
||||
export type TabsFieldDescriptionServerComponent = FieldDescriptionServerComponent<TabsField>
|
||||
|
||||
export type TabsFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<TabsFieldClientWithoutType>
|
||||
|
||||
export type TabsFieldErrorServerComponent = FieldErrorServerComponent<TabsField>
|
||||
|
||||
export type TabsFieldErrorClientComponent = FieldErrorClientComponent<TabsFieldClientWithoutType>
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
import type React from 'react'
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { TextFieldClient } from '../../fields/config/types.js'
|
||||
import type { TextField, TextFieldClient } from '../../fields/config/types.js'
|
||||
import type { TextFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type TextFieldClientWithoutType = MarkOptional<TextFieldClient, 'type'>
|
||||
|
||||
export type TextFieldProps = {
|
||||
readonly field: MarkOptional<TextFieldClient, 'type'>
|
||||
readonly inputRef?: React.RefObject<HTMLInputElement>
|
||||
readonly onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
readonly validate?: TextFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<TextFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type TextFieldLabelComponent = LabelComponent<'text'>
|
||||
export type TextFieldLabelServerComponent = FieldLabelServerComponent<TextField>
|
||||
|
||||
export type TextFieldDescriptionComponent = DescriptionComponent<'text'>
|
||||
export type TextFieldLabelClientComponent = FieldLabelClientComponent<TextFieldClientWithoutType>
|
||||
|
||||
export type TextFieldErrorComponent = ErrorComponent<'text'>
|
||||
export type TextFieldDescriptionServerComponent = FieldDescriptionServerComponent<TextField>
|
||||
|
||||
export type TextFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<TextFieldClientWithoutType>
|
||||
|
||||
export type TextFieldErrorServerComponent = FieldErrorServerComponent<TextField>
|
||||
|
||||
export type TextFieldErrorClientComponent = FieldErrorClientComponent<TextFieldClientWithoutType>
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
import type React from 'react'
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { TextareaFieldClient } from '../../fields/config/types.js'
|
||||
import type { TextareaField, TextareaFieldClient } from '../../fields/config/types.js'
|
||||
import type { TextareaFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type TextareaFieldClientWithoutType = MarkOptional<TextareaFieldClient, 'type'>
|
||||
|
||||
export type TextareaFieldProps = {
|
||||
readonly field: MarkOptional<TextareaFieldClient, 'type'>
|
||||
readonly inputRef?: React.Ref<HTMLInputElement>
|
||||
readonly onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
|
||||
readonly validate?: TextareaFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<TextareaFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type TextareaFieldLabelComponent = LabelComponent<'textarea'>
|
||||
export type TextareaFieldLabelServerComponent = FieldLabelServerComponent<TextareaField>
|
||||
|
||||
export type TextareaFieldDescriptionComponent = DescriptionComponent<'textarea'>
|
||||
export type TextareaFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<TextareaFieldClientWithoutType>
|
||||
|
||||
export type TextareaFieldErrorComponent = ErrorComponent<'textarea'>
|
||||
export type TextareaFieldDescriptionServerComponent = FieldDescriptionServerComponent<TextareaField>
|
||||
|
||||
export type TextareaFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<TextareaFieldClientWithoutType>
|
||||
|
||||
export type TextareaFieldErrorServerComponent = FieldErrorServerComponent<TextareaField>
|
||||
|
||||
export type TextareaFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<TextareaFieldClientWithoutType>
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { UploadFieldClient } from '../../fields/config/types.js'
|
||||
import type { UploadField, UploadFieldClient } from '../../fields/config/types.js'
|
||||
import type { UploadFieldValidation } from '../../fields/validations.js'
|
||||
import type { ErrorComponent } from '../forms/Error.js'
|
||||
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
|
||||
import type { FieldErrorClientComponent, FieldErrorServerComponent } from '../forms/Error.js'
|
||||
import type {
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelServerComponent,
|
||||
FormFieldBase,
|
||||
} from '../types.js'
|
||||
|
||||
type UploadFieldClientWithoutType = MarkOptional<UploadFieldClient, 'type'>
|
||||
|
||||
export type UploadFieldProps = {
|
||||
readonly field: MarkOptional<UploadFieldClient, 'type'>
|
||||
readonly validate?: UploadFieldValidation
|
||||
} & Omit<FormFieldBase, 'validate'>
|
||||
} & Omit<FormFieldBase<UploadFieldClientWithoutType>, 'validate'>
|
||||
|
||||
export type UploadFieldLabelComponent = LabelComponent<'upload'>
|
||||
export type UploadFieldLabelServerComponent = FieldLabelServerComponent<UploadField>
|
||||
|
||||
export type UploadFieldDescriptionComponent = DescriptionComponent<'upload'>
|
||||
export type UploadFieldLabelClientComponent =
|
||||
FieldLabelClientComponent<UploadFieldClientWithoutType>
|
||||
|
||||
export type UploadFieldErrorComponent = ErrorComponent<'upload'>
|
||||
export type UploadFieldDescriptionServerComponent = FieldDescriptionServerComponent<UploadField>
|
||||
|
||||
export type UploadFieldDescriptionClientComponent =
|
||||
FieldDescriptionClientComponent<UploadFieldClientWithoutType>
|
||||
|
||||
export type UploadFieldErrorServerComponent = FieldErrorServerComponent<UploadField>
|
||||
|
||||
export type UploadFieldErrorClientComponent =
|
||||
FieldErrorClientComponent<UploadFieldClientWithoutType>
|
||||
|
||||
38
packages/payload/src/admin/forms/Description.ts
Normal file
38
packages/payload/src/admin/forms/Description.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { LabelFunction, ServerProps } from '../../config/types.js'
|
||||
import type { ClientField, Field } from '../../fields/config/types.js'
|
||||
import type { MappedComponent } from '../types.js'
|
||||
|
||||
export type DescriptionFunction = LabelFunction
|
||||
|
||||
type ClientFieldWithOptionalType = MarkOptional<ClientField, 'type'>
|
||||
|
||||
export type FieldDescriptionClientComponent<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = React.ComponentType<FieldDescriptionClientProps<TFieldClient>>
|
||||
|
||||
export type FieldDescriptionServerComponent<TFieldServer extends Field = Field> =
|
||||
React.ComponentType<FieldDescriptionServerProps<TFieldServer>>
|
||||
|
||||
export type StaticDescription = Record<string, string> | string
|
||||
|
||||
export type Description = DescriptionFunction | StaticDescription
|
||||
|
||||
export type GenericDescriptionProps = {
|
||||
readonly Description?: MappedComponent
|
||||
readonly className?: string
|
||||
readonly description?: StaticDescription
|
||||
readonly marginPlacement?: 'bottom' | 'top'
|
||||
}
|
||||
|
||||
export type FieldDescriptionServerProps<TFieldServer extends Field = Field> = {
|
||||
field: TFieldServer
|
||||
} & GenericDescriptionProps &
|
||||
Partial<ServerProps>
|
||||
|
||||
export type FieldDescriptionClientProps<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = {
|
||||
field: TFieldClient
|
||||
} & GenericDescriptionProps
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { CustomComponent, ServerProps } from '../../config/types.js'
|
||||
import type { FieldTypes } from '../../fields/config/types.js'
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { ServerProps } from '../../config/types.js'
|
||||
import type { ClientField, Field } from '../../fields/config/types.js'
|
||||
import type { MappedComponent } from '../types.js'
|
||||
|
||||
export type GenericErrorProps = {
|
||||
@@ -10,9 +12,23 @@ export type GenericErrorProps = {
|
||||
readonly showError?: boolean
|
||||
}
|
||||
|
||||
export type ErrorProps<T extends 'hidden' | FieldTypes = any> = {
|
||||
type: T
|
||||
type ClientFieldWithOptionalType = MarkOptional<ClientField, 'type'>
|
||||
|
||||
export type FieldErrorClientProps<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = {
|
||||
field: TFieldClient
|
||||
} & GenericErrorProps
|
||||
|
||||
export type FieldErrorServerProps<TFieldServer extends Field> = {
|
||||
field: TFieldServer
|
||||
} & GenericErrorProps &
|
||||
Partial<ServerProps>
|
||||
|
||||
export type ErrorComponent<T extends 'hidden' | FieldTypes = any> = CustomComponent<ErrorProps<T>>
|
||||
export type FieldErrorClientComponent<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = React.ComponentType<FieldErrorClientProps<TFieldClient>>
|
||||
|
||||
export type FieldErrorServerComponent<TFieldServer extends Field = Field> = React.ComponentType<
|
||||
FieldErrorServerProps<TFieldServer>
|
||||
>
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { User } from '../../auth/types.js'
|
||||
import type { Locale } from '../../config/types.js'
|
||||
import type { Validate } from '../../fields/config/types.js'
|
||||
import type { ClientField, Validate } from '../../fields/config/types.js'
|
||||
import type { DocumentPreferences } from '../../preferences/types.js'
|
||||
import type { ErrorProps } from './Error.js'
|
||||
import type { FieldDescriptionProps } from './FieldDescription.js'
|
||||
import type { LabelProps } from './Label.js'
|
||||
import type { FieldDescriptionClientProps } from './Description.js'
|
||||
import type { FieldErrorClientProps } from './Error.js'
|
||||
import type { FieldLabelClientProps } from './Label.js'
|
||||
|
||||
// TODO: Check if we still need this. Shouldnt most of it be present in the field type?
|
||||
export type FormFieldBase = {
|
||||
readonly descriptionProps?: FieldDescriptionProps
|
||||
export type FormFieldBase<
|
||||
TFieldClient extends MarkOptional<ClientField, 'type'> = MarkOptional<ClientField, 'type'>,
|
||||
> = {
|
||||
readonly descriptionProps?: FieldDescriptionClientProps<TFieldClient>
|
||||
readonly docPreferences?: DocumentPreferences
|
||||
readonly errorProps?: ErrorProps
|
||||
readonly errorProps?: FieldErrorClientProps<TFieldClient>
|
||||
readonly field: TFieldClient
|
||||
/**
|
||||
* forceRender is added by RenderField automatically
|
||||
* `forceRender` is added by RenderField automatically.
|
||||
*/
|
||||
readonly forceRender?: boolean
|
||||
readonly labelProps?: LabelProps
|
||||
readonly labelProps?: FieldLabelClientProps<TFieldClient>
|
||||
readonly locale?: Locale
|
||||
/**
|
||||
* forceRender is added by RenderField automatically. This should be used instead of field.admin.readOnly
|
||||
* `readOnly` is added by RenderField automatically. This should be used instead of `field.admin.readOnly`.
|
||||
*/
|
||||
readonly readOnly?: boolean
|
||||
readonly user?: User
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import type { CustomComponent, LabelFunction, ServerProps } from '../../config/types.js'
|
||||
import type { FieldTypes } from '../../fields/config/types.js'
|
||||
import type { MappedComponent } from '../types.js'
|
||||
|
||||
export type DescriptionFunction = LabelFunction
|
||||
|
||||
export type DescriptionComponent<T extends 'hidden' | FieldTypes = any> = CustomComponent<
|
||||
FieldDescriptionProps<T>
|
||||
>
|
||||
|
||||
export type StaticDescription = Record<string, string> | string
|
||||
|
||||
export type Description = DescriptionFunction | StaticDescription
|
||||
export type GenericDescriptionProps = {
|
||||
readonly Description?: MappedComponent
|
||||
readonly className?: string
|
||||
readonly description?: StaticDescription
|
||||
readonly marginPlacement?: 'bottom' | 'top'
|
||||
}
|
||||
export type FieldDescriptionProps<T extends 'hidden' | FieldTypes = any> = {
|
||||
type: T
|
||||
} & GenericDescriptionProps &
|
||||
Partial<ServerProps>
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { CustomComponent, ServerProps, StaticLabel } from '../../config/types.js'
|
||||
import type { FieldTypes } from '../../fields/config/types.js'
|
||||
import type { MarkOptional } from 'ts-essentials'
|
||||
|
||||
import type { ServerProps, StaticLabel } from '../../config/types.js'
|
||||
import type { ClientField, Field } from '../../fields/config/types.js'
|
||||
import type { MappedComponent } from '../types.js'
|
||||
|
||||
export type GenericLabelProps = {
|
||||
@@ -11,14 +13,28 @@ export type GenericLabelProps = {
|
||||
readonly unstyled?: boolean
|
||||
}
|
||||
|
||||
export type LabelProps<T extends 'hidden' | FieldTypes = any> = {
|
||||
type: T
|
||||
type ClientFieldWithOptionalType = MarkOptional<ClientField, 'type'>
|
||||
|
||||
export type FieldLabelClientProps<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = {
|
||||
field: TFieldClient
|
||||
} & GenericLabelProps
|
||||
|
||||
export type FieldLabelServerProps<TFieldServer extends Field> = {
|
||||
field: TFieldServer
|
||||
} & GenericLabelProps &
|
||||
Partial<ServerProps>
|
||||
|
||||
export type SanitizedLabelProps<T extends 'hidden' | FieldTypes = any> = Omit<
|
||||
LabelProps<T>,
|
||||
export type SanitizedLabelProps<TFieldClient extends ClientField> = Omit<
|
||||
FieldLabelClientProps<TFieldClient>,
|
||||
'label' | 'required'
|
||||
>
|
||||
|
||||
export type LabelComponent<T extends 'hidden' | FieldTypes = any> = CustomComponent<LabelProps<T>>
|
||||
export type FieldLabelClientComponent<
|
||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||
> = React.ComponentType<FieldLabelClientProps<TFieldClient>>
|
||||
|
||||
export type FieldLabelServerComponent<TFieldServer extends Field = Field> = React.ComponentType<
|
||||
FieldLabelServerProps<TFieldServer>
|
||||
>
|
||||
|
||||
@@ -33,172 +33,237 @@ export type {
|
||||
} from './elements/WithServerSideProps.js'
|
||||
|
||||
export type {
|
||||
ArrayFieldDescriptionComponent,
|
||||
ArrayFieldErrorComponent,
|
||||
ArrayFieldLabelComponent,
|
||||
ArrayFieldDescriptionClientComponent,
|
||||
ArrayFieldDescriptionServerComponent,
|
||||
ArrayFieldErrorClientComponent,
|
||||
ArrayFieldErrorServerComponent,
|
||||
ArrayFieldLabelClientComponent,
|
||||
ArrayFieldLabelServerComponent,
|
||||
ArrayFieldProps,
|
||||
} from './fields/Array.js'
|
||||
|
||||
export type {
|
||||
BlockFieldDescriptionComponent,
|
||||
BlockFieldErrorComponent,
|
||||
BlockFieldLabelComponent,
|
||||
BlockFieldDescriptionClientComponent,
|
||||
BlockFieldDescriptionServerComponent,
|
||||
BlockFieldErrorClientComponent,
|
||||
BlockFieldErrorServerComponent,
|
||||
BlockFieldLabelClientComponent,
|
||||
BlockFieldLabelServerComponent,
|
||||
BlockFieldProps,
|
||||
} from './fields/Blocks.js'
|
||||
|
||||
export type {
|
||||
CheckboxFieldDescriptionComponent,
|
||||
CheckboxFieldErrorComponent,
|
||||
CheckboxFieldLabelComponent,
|
||||
CheckboxFieldDescriptionClientComponent,
|
||||
CheckboxFieldDescriptionServerComponent,
|
||||
CheckboxFieldErrorClientComponent,
|
||||
CheckboxFieldErrorServerComponent,
|
||||
CheckboxFieldLabelClientComponent,
|
||||
CheckboxFieldLabelServerComponent,
|
||||
CheckboxFieldProps,
|
||||
} from './fields/Checkbox.js'
|
||||
|
||||
export type {
|
||||
CodeFieldDescriptionComponent,
|
||||
CodeFieldErrorComponent,
|
||||
CodeFieldLabelComponent,
|
||||
CodeFieldDescriptionClientComponent,
|
||||
CodeFieldDescriptionServerComponent,
|
||||
CodeFieldErrorClientComponent,
|
||||
CodeFieldErrorServerComponent,
|
||||
CodeFieldLabelClientComponent,
|
||||
CodeFieldLabelServerComponent,
|
||||
CodeFieldProps,
|
||||
} from './fields/Code.js'
|
||||
|
||||
export type {
|
||||
CollapsibleFieldDescriptionComponent,
|
||||
CollapsibleFieldErrorComponent,
|
||||
CollapsibleFieldLabelComponent,
|
||||
CollapsibleFieldDescriptionClientComponent,
|
||||
CollapsibleFieldDescriptionServerComponent,
|
||||
CollapsibleFieldErrorClientComponent,
|
||||
CollapsibleFieldErrorServerComponent,
|
||||
CollapsibleFieldLabelClientComponent,
|
||||
CollapsibleFieldLabelServerComponent,
|
||||
CollapsibleFieldProps,
|
||||
} from './fields/Collapsible.js'
|
||||
|
||||
export type {
|
||||
DateFieldDescriptionComponent,
|
||||
DateFieldErrorComponent,
|
||||
DateFieldLabelComponent,
|
||||
DateFieldDescriptionClientComponent,
|
||||
DateFieldDescriptionServerComponent,
|
||||
DateFieldErrorClientComponent,
|
||||
DateFieldErrorServerComponent,
|
||||
DateFieldLabelClientComponent,
|
||||
DateFieldLabelServerComponent,
|
||||
DateFieldProps,
|
||||
} from './fields/Date.js'
|
||||
|
||||
export type {
|
||||
EmailFieldDescriptionComponent,
|
||||
EmailFieldErrorComponent,
|
||||
EmailFieldLabelComponent,
|
||||
EmailFieldDescriptionClientComponent,
|
||||
EmailFieldDescriptionServerComponent,
|
||||
EmailFieldErrorClientComponent,
|
||||
EmailFieldErrorServerComponent,
|
||||
EmailFieldLabelClientComponent,
|
||||
EmailFieldLabelServerComponent,
|
||||
EmailFieldProps,
|
||||
} from './fields/Email.js'
|
||||
|
||||
export type {
|
||||
GroupFieldDescriptionComponent,
|
||||
GroupFieldErrorComponent,
|
||||
GroupFieldLabelComponent,
|
||||
GroupFieldDescriptionClientComponent,
|
||||
GroupFieldDescriptionServerComponent,
|
||||
GroupFieldErrorClientComponent,
|
||||
GroupFieldErrorServerComponent,
|
||||
GroupFieldLabelClientComponent,
|
||||
GroupFieldLabelServerComponent,
|
||||
GroupFieldProps,
|
||||
} from './fields/Group.js'
|
||||
|
||||
export type {
|
||||
HiddenFieldDescriptionComponent,
|
||||
HiddenFieldErrorComponent,
|
||||
HiddenFieldLabelComponent,
|
||||
HiddenFieldProps,
|
||||
} from './fields/Hidden.js'
|
||||
export type { HiddenFieldProps } from './fields/Hidden.js'
|
||||
|
||||
export type {
|
||||
JSONFieldDescriptionComponent,
|
||||
JSONFieldErrorComponent,
|
||||
JSONFieldLabelComponent,
|
||||
JSONFieldDescriptionClientComponent,
|
||||
JSONFieldDescriptionServerComponent,
|
||||
JSONFieldErrorClientComponent,
|
||||
JSONFieldErrorServerComponent,
|
||||
JSONFieldLabelClientComponent,
|
||||
JSONFieldLabelServerComponent,
|
||||
JSONFieldProps,
|
||||
} from './fields/JSON.js'
|
||||
|
||||
export type {
|
||||
NumberFieldDescriptionComponent,
|
||||
NumberFieldErrorComponent,
|
||||
NumberFieldLabelComponent,
|
||||
NumberFieldDescriptionClientComponent,
|
||||
NumberFieldDescriptionServerComponent,
|
||||
NumberFieldErrorClientComponent,
|
||||
NumberFieldErrorServerComponent,
|
||||
NumberFieldLabelClientComponent,
|
||||
NumberFieldLabelServerComponent,
|
||||
NumberFieldProps,
|
||||
} from './fields/Number.js'
|
||||
|
||||
export type {
|
||||
PointFieldDescriptionComponent,
|
||||
PointFieldErrorComponent,
|
||||
PointFieldLabelComponent,
|
||||
PointFieldDescriptionClientComponent,
|
||||
PointFieldDescriptionServerComponent,
|
||||
PointFieldErrorClientComponent,
|
||||
PointFieldErrorServerComponent,
|
||||
PointFieldLabelClientComponent,
|
||||
PointFieldLabelServerComponent,
|
||||
PointFieldProps,
|
||||
} from './fields/Point.js'
|
||||
|
||||
export type {
|
||||
RadioFieldDescriptionComponent,
|
||||
RadioFieldErrorComponent,
|
||||
RadioFieldLabelComponent,
|
||||
RadioFieldDescriptionClientComponent,
|
||||
RadioFieldDescriptionServerComponent,
|
||||
RadioFieldErrorClientComponent,
|
||||
RadioFieldErrorServerComponent,
|
||||
RadioFieldLabelClientComponent,
|
||||
RadioFieldLabelServerComponent,
|
||||
RadioFieldProps,
|
||||
} from './fields/Radio.js'
|
||||
|
||||
export type {
|
||||
RelationshipFieldDescriptionComponent,
|
||||
RelationshipFieldErrorComponent,
|
||||
RelationshipFieldLabelComponent,
|
||||
RelationshipFieldDescriptionClientComponent,
|
||||
RelationshipFieldDescriptionServerComponent,
|
||||
RelationshipFieldErrorClientComponent,
|
||||
RelationshipFieldErrorServerComponent,
|
||||
RelationshipFieldLabelClientComponent,
|
||||
RelationshipFieldLabelServerComponent,
|
||||
RelationshipFieldProps,
|
||||
} from './fields/Relationship.js'
|
||||
|
||||
export type {
|
||||
RichTextFieldDescriptionComponent,
|
||||
RichTextFieldErrorComponent,
|
||||
RichTextFieldLabelComponent,
|
||||
RichTextFieldDescriptionClientComponent,
|
||||
RichTextFieldDescriptionServerComponent,
|
||||
RichTextFieldErrorClientComponent,
|
||||
RichTextFieldErrorServerComponent,
|
||||
RichTextFieldLabelClientComponent,
|
||||
RichTextFieldLabelServerComponent,
|
||||
RichTextFieldProps,
|
||||
} from './fields/RichText.js'
|
||||
|
||||
export type {
|
||||
RowFieldDescriptionComponent,
|
||||
RowFieldErrorComponent,
|
||||
RowFieldLabelComponent,
|
||||
RowFieldDescriptionClientComponent,
|
||||
RowFieldDescriptionServerComponent,
|
||||
RowFieldErrorClientComponent,
|
||||
RowFieldErrorServerComponent,
|
||||
RowFieldLabelClientComponent,
|
||||
RowFieldLabelServerComponent,
|
||||
RowFieldProps,
|
||||
} from './fields/Row.js'
|
||||
|
||||
export type {
|
||||
SelectFieldDescriptionComponent,
|
||||
SelectFieldErrorComponent,
|
||||
SelectFieldLabelComponent,
|
||||
SelectFieldDescriptionClientComponent,
|
||||
SelectFieldDescriptionServerComponent,
|
||||
SelectFieldErrorClientComponent,
|
||||
SelectFieldErrorServerComponent,
|
||||
SelectFieldLabelClientComponent,
|
||||
SelectFieldLabelServerComponent,
|
||||
SelectFieldProps,
|
||||
} from './fields/Select.js'
|
||||
|
||||
export type {
|
||||
ClientTab,
|
||||
TabsFieldDescriptionComponent,
|
||||
TabsFieldErrorComponent,
|
||||
TabsFieldLabelComponent,
|
||||
TabsFieldDescriptionClientComponent,
|
||||
TabsFieldDescriptionServerComponent,
|
||||
TabsFieldErrorClientComponent,
|
||||
TabsFieldErrorServerComponent,
|
||||
TabsFieldLabelClientComponent,
|
||||
TabsFieldLabelServerComponent,
|
||||
TabsFieldProps,
|
||||
} from './fields/Tabs.js'
|
||||
|
||||
export type {
|
||||
TextFieldDescriptionComponent,
|
||||
TextFieldErrorComponent,
|
||||
TextFieldLabelComponent,
|
||||
TextFieldDescriptionClientComponent,
|
||||
TextFieldDescriptionServerComponent,
|
||||
TextFieldErrorClientComponent,
|
||||
TextFieldErrorServerComponent,
|
||||
TextFieldLabelClientComponent,
|
||||
TextFieldLabelServerComponent,
|
||||
TextFieldProps,
|
||||
} from './fields/Text.js'
|
||||
|
||||
export type {
|
||||
TextareaFieldDescriptionComponent,
|
||||
TextareaFieldErrorComponent,
|
||||
TextareaFieldLabelComponent,
|
||||
TextareaFieldDescriptionClientComponent,
|
||||
TextareaFieldDescriptionServerComponent,
|
||||
TextareaFieldErrorClientComponent,
|
||||
TextareaFieldErrorServerComponent,
|
||||
TextareaFieldLabelClientComponent,
|
||||
TextareaFieldLabelServerComponent,
|
||||
TextareaFieldProps,
|
||||
} from './fields/Textarea.js'
|
||||
|
||||
export type {
|
||||
UploadFieldDescriptionComponent,
|
||||
UploadFieldErrorComponent,
|
||||
UploadFieldLabelComponent,
|
||||
UploadFieldDescriptionClientComponent,
|
||||
UploadFieldDescriptionServerComponent,
|
||||
UploadFieldErrorClientComponent,
|
||||
UploadFieldErrorServerComponent,
|
||||
UploadFieldLabelClientComponent,
|
||||
UploadFieldLabelServerComponent,
|
||||
UploadFieldProps,
|
||||
} from './fields/Upload.js'
|
||||
|
||||
export type { ErrorComponent, ErrorProps, GenericErrorProps } from './forms/Error.js'
|
||||
|
||||
export type { FormFieldBase } from './forms/Field.js'
|
||||
|
||||
export type {
|
||||
Description,
|
||||
DescriptionComponent,
|
||||
DescriptionFunction,
|
||||
FieldDescriptionProps,
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionClientProps,
|
||||
FieldDescriptionServerComponent,
|
||||
FieldDescriptionServerProps,
|
||||
GenericDescriptionProps,
|
||||
StaticDescription,
|
||||
} from './forms/FieldDescription.js'
|
||||
} from './forms/Description.js'
|
||||
|
||||
export type {
|
||||
FieldErrorClientComponent,
|
||||
FieldErrorClientProps,
|
||||
FieldErrorServerComponent,
|
||||
FieldErrorServerProps,
|
||||
GenericErrorProps,
|
||||
} from './forms/Error.js'
|
||||
|
||||
export type { FormFieldBase } from './forms/Field.js'
|
||||
|
||||
export type { Data, FilterOptionsResult, FormField, FormState, Row } from './forms/Form.js'
|
||||
|
||||
export type {
|
||||
FieldLabelClientComponent,
|
||||
FieldLabelClientProps,
|
||||
FieldLabelServerComponent,
|
||||
FieldLabelServerProps,
|
||||
GenericLabelProps,
|
||||
LabelComponent,
|
||||
LabelProps,
|
||||
SanitizedLabelProps,
|
||||
} from './forms/Label.js'
|
||||
|
||||
@@ -241,14 +306,20 @@ export type MappedComponent<TComponentClientProps extends JsonObject = JsonObjec
|
||||
export type CreateMappedComponent = {
|
||||
<T extends JsonObject>(
|
||||
component: { Component: React.FC<T> } | PayloadComponent<T> | null,
|
||||
props: object,
|
||||
props: {
|
||||
clientProps?: JsonObject
|
||||
serverProps?: object
|
||||
},
|
||||
fallback: React.FC,
|
||||
identifier: string,
|
||||
): MappedComponent<T>
|
||||
|
||||
<T extends JsonObject>(
|
||||
components: ({ Component: React.FC<T> } | PayloadComponent<T>)[],
|
||||
props: object,
|
||||
props: {
|
||||
clientProps?: JsonObject
|
||||
serverProps?: object
|
||||
},
|
||||
fallback: React.FC,
|
||||
identifier: string,
|
||||
): MappedComponent<T>[]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { MappedComponent } from '../../admin/types.js'
|
||||
import type { MappedComponent, StaticDescription } from '../../admin/types.js'
|
||||
import type { MappedView } from '../../admin/views/types.js'
|
||||
import type { LivePreviewConfig, ServerOnlyLivePreviewProperties } from '../../config/types.js'
|
||||
import type { ClientField } from '../../fields/config/client.js'
|
||||
@@ -46,7 +46,7 @@ export type ClientCollectionConfig = {
|
||||
}
|
||||
}
|
||||
}
|
||||
description?: Record<string, string> | string
|
||||
description?: StaticDescription
|
||||
livePreview?: Omit<LivePreviewConfig, ServerOnlyLivePreviewProperties>
|
||||
} & Omit<
|
||||
SanitizedCollectionConfig['admin'],
|
||||
|
||||
@@ -398,14 +398,14 @@ export type EditViewConfig = {
|
||||
)
|
||||
|
||||
export type ServerProps = {
|
||||
[key: string]: unknown
|
||||
i18n: I18nClient
|
||||
locale?: Locale
|
||||
params?: { [key: string]: string | string[] | undefined }
|
||||
payload: Payload
|
||||
permissions?: Permissions
|
||||
searchParams?: { [key: string]: string | string[] | undefined }
|
||||
user?: TypedUser
|
||||
readonly i18n: I18nClient
|
||||
readonly locale?: Locale
|
||||
readonly params?: { [key: string]: string | string[] | undefined }
|
||||
readonly payload: Payload
|
||||
readonly permissions?: Permissions
|
||||
readonly [key: string]: unknown
|
||||
readonly searchParams?: { [key: string]: string | string[] | undefined }
|
||||
readonly user?: TypedUser
|
||||
}
|
||||
|
||||
export const serverProps: (keyof ServerProps)[] = [
|
||||
|
||||
@@ -42,7 +42,6 @@ export {
|
||||
export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js'
|
||||
|
||||
export { getDataByPath } from '../utilities/getDataByPath.js'
|
||||
|
||||
export { getSiblingData } from '../utilities/getSiblingData.js'
|
||||
|
||||
export { getUniqueListBy } from '../utilities/getUniqueListBy.js'
|
||||
|
||||
@@ -6,16 +6,97 @@ import type { CSSProperties } from 'react'
|
||||
import type { DeepUndefinable } from 'ts-essentials'
|
||||
|
||||
import type { RichTextAdapter, RichTextAdapterProvider } from '../../admin/RichText.js'
|
||||
import type { ErrorComponent } from '../../admin/forms/Error.js'
|
||||
import type {
|
||||
ArrayFieldErrorClientComponent,
|
||||
ArrayFieldErrorServerComponent,
|
||||
ArrayFieldLabelClientComponent,
|
||||
ArrayFieldLabelServerComponent,
|
||||
ArrayFieldProps,
|
||||
BlockFieldErrorClientComponent,
|
||||
BlockFieldErrorServerComponent,
|
||||
BlockFieldProps,
|
||||
CheckboxFieldErrorClientComponent,
|
||||
CheckboxFieldErrorServerComponent,
|
||||
CheckboxFieldLabelClientComponent,
|
||||
CheckboxFieldLabelServerComponent,
|
||||
CheckboxFieldProps,
|
||||
ClientTab,
|
||||
CodeFieldErrorClientComponent,
|
||||
CodeFieldErrorServerComponent,
|
||||
CodeFieldLabelClientComponent,
|
||||
CodeFieldLabelServerComponent,
|
||||
CodeFieldProps,
|
||||
CollapsibleFieldLabelClientComponent,
|
||||
CollapsibleFieldLabelServerComponent,
|
||||
CollapsibleFieldProps,
|
||||
ConditionalDateProps,
|
||||
DateFieldErrorClientComponent,
|
||||
DateFieldErrorServerComponent,
|
||||
DateFieldLabelClientComponent,
|
||||
DateFieldLabelServerComponent,
|
||||
DateFieldProps,
|
||||
Description,
|
||||
DescriptionComponent,
|
||||
LabelComponent,
|
||||
EmailFieldErrorClientComponent,
|
||||
EmailFieldErrorServerComponent,
|
||||
EmailFieldLabelClientComponent,
|
||||
EmailFieldLabelServerComponent,
|
||||
EmailFieldProps,
|
||||
FieldDescriptionClientComponent,
|
||||
FieldDescriptionServerComponent,
|
||||
GroupFieldLabelClientComponent,
|
||||
GroupFieldLabelServerComponent,
|
||||
GroupFieldProps,
|
||||
HiddenFieldProps,
|
||||
JSONFieldErrorClientComponent,
|
||||
JSONFieldErrorServerComponent,
|
||||
JSONFieldLabelClientComponent,
|
||||
JSONFieldLabelServerComponent,
|
||||
JSONFieldProps,
|
||||
MappedComponent,
|
||||
NumberFieldErrorClientComponent,
|
||||
NumberFieldErrorServerComponent,
|
||||
NumberFieldLabelClientComponent,
|
||||
NumberFieldLabelServerComponent,
|
||||
NumberFieldProps,
|
||||
PointFieldErrorClientComponent,
|
||||
PointFieldErrorServerComponent,
|
||||
PointFieldLabelClientComponent,
|
||||
PointFieldLabelServerComponent,
|
||||
PointFieldProps,
|
||||
RadioFieldErrorClientComponent,
|
||||
RadioFieldErrorServerComponent,
|
||||
RadioFieldLabelClientComponent,
|
||||
RadioFieldLabelServerComponent,
|
||||
RadioFieldProps,
|
||||
RelationshipFieldErrorClientComponent,
|
||||
RelationshipFieldErrorServerComponent,
|
||||
RelationshipFieldLabelClientComponent,
|
||||
RelationshipFieldLabelServerComponent,
|
||||
RelationshipFieldProps,
|
||||
RichTextFieldProps,
|
||||
RowFieldProps,
|
||||
RowLabelComponent,
|
||||
SelectFieldErrorClientComponent,
|
||||
SelectFieldErrorServerComponent,
|
||||
SelectFieldLabelClientComponent,
|
||||
SelectFieldLabelServerComponent,
|
||||
SelectFieldProps,
|
||||
StaticDescription,
|
||||
TabsFieldProps,
|
||||
TextFieldErrorClientComponent,
|
||||
TextFieldErrorServerComponent,
|
||||
TextFieldLabelClientComponent,
|
||||
TextFieldLabelServerComponent,
|
||||
TextareaFieldErrorClientComponent,
|
||||
TextareaFieldErrorServerComponent,
|
||||
TextareaFieldLabelClientComponent,
|
||||
TextareaFieldLabelServerComponent,
|
||||
TextareaFieldProps,
|
||||
UploadFieldErrorClientComponent,
|
||||
UploadFieldErrorServerComponent,
|
||||
UploadFieldLabelClientComponent,
|
||||
UploadFieldLabelServerComponent,
|
||||
UploadFieldProps,
|
||||
} from '../../admin/types.js'
|
||||
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'
|
||||
import type {
|
||||
@@ -148,7 +229,7 @@ type Admin = {
|
||||
className?: string
|
||||
components?: {
|
||||
Cell?: CustomComponent
|
||||
Description?: DescriptionComponent
|
||||
Description?: CustomComponent<FieldDescriptionClientComponent | FieldDescriptionServerComponent>
|
||||
Field?: CustomComponent
|
||||
/**
|
||||
* The Filter component has to be a client component
|
||||
@@ -339,8 +420,8 @@ export type NumberField = {
|
||||
/** Set this property to a string that will be used for browser autocomplete. */
|
||||
autoComplete?: string
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<NumberFieldErrorClientComponent | NumberFieldErrorServerComponent>
|
||||
Label?: CustomComponent<NumberFieldLabelClientComponent | NumberFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -392,8 +473,8 @@ export type TextField = {
|
||||
admin?: {
|
||||
autoComplete?: string
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<TextFieldErrorClientComponent | TextFieldErrorServerComponent>
|
||||
Label?: CustomComponent<TextFieldLabelClientComponent | TextFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -441,8 +522,8 @@ export type EmailField = {
|
||||
admin?: {
|
||||
autoComplete?: string
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<EmailFieldErrorClientComponent | EmailFieldErrorServerComponent>
|
||||
Label?: CustomComponent<EmailFieldLabelClientComponent | EmailFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -468,8 +549,8 @@ export type EmailFieldClient = {
|
||||
export type TextareaField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<TextareaFieldErrorClientComponent | TextareaFieldErrorServerComponent>
|
||||
Label?: CustomComponent<TextareaFieldLabelClientComponent | TextareaFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -499,8 +580,8 @@ export type TextareaFieldClient = {
|
||||
export type CheckboxField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<CheckboxFieldErrorClientComponent | CheckboxFieldErrorServerComponent>
|
||||
Label?: CustomComponent<CheckboxFieldLabelClientComponent | CheckboxFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -524,8 +605,8 @@ export type CheckboxFieldClient = {
|
||||
export type DateField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<DateFieldErrorClientComponent | DateFieldErrorServerComponent>
|
||||
Label?: CustomComponent<DateFieldLabelClientComponent | DateFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -552,7 +633,7 @@ export type DateFieldClient = {
|
||||
export type GroupField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Label?: LabelComponent
|
||||
Label?: CustomComponent<GroupFieldLabelClientComponent | GroupFieldLabelServerComponent>
|
||||
} & Admin['components']
|
||||
hideGutter?: boolean
|
||||
} & Admin
|
||||
@@ -598,7 +679,9 @@ export type CollapsibleField = {
|
||||
| {
|
||||
admin: {
|
||||
components: {
|
||||
Label?: LabelComponent
|
||||
Label?: CustomComponent<
|
||||
CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent
|
||||
>
|
||||
RowLabel: RowLabelComponent
|
||||
} & Admin['components']
|
||||
initCollapsed?: boolean
|
||||
@@ -608,7 +691,9 @@ export type CollapsibleField = {
|
||||
| {
|
||||
admin?: {
|
||||
components?: {
|
||||
Label?: LabelComponent
|
||||
Label?: CustomComponent<
|
||||
CollapsibleFieldLabelClientComponent | CollapsibleFieldLabelServerComponent
|
||||
>
|
||||
} & Admin['components']
|
||||
initCollapsed?: boolean
|
||||
} & Admin
|
||||
@@ -742,8 +827,8 @@ export type UIFieldClient = {
|
||||
export type UploadField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<UploadFieldErrorClientComponent | UploadFieldErrorServerComponent>
|
||||
Label?: CustomComponent<UploadFieldLabelClientComponent | UploadFieldLabelServerComponent>
|
||||
} & Admin['components']
|
||||
}
|
||||
displayPreview?: boolean
|
||||
@@ -772,8 +857,8 @@ export type UploadFieldClient = {
|
||||
export type CodeField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<CodeFieldErrorClientComponent | CodeFieldErrorServerComponent>
|
||||
Label?: CustomComponent<CodeFieldLabelClientComponent | CodeFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -802,8 +887,8 @@ export type CodeFieldClient = {
|
||||
export type JSONField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<JSONFieldErrorClientComponent | JSONFieldErrorServerComponent>
|
||||
Label?: CustomComponent<JSONFieldLabelClientComponent | JSONFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -835,8 +920,8 @@ export type JSONFieldClient = {
|
||||
export type SelectField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<SelectFieldErrorClientComponent | SelectFieldErrorServerComponent>
|
||||
Label?: CustomComponent<SelectFieldLabelClientComponent | SelectFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -920,8 +1005,12 @@ type SharedRelationshipPropertiesClient = FieldBaseClient &
|
||||
type RelationshipAdmin = {
|
||||
allowCreate?: boolean
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<
|
||||
RelationshipFieldErrorClientComponent | RelationshipFieldErrorServerComponent
|
||||
>
|
||||
Label?: CustomComponent<
|
||||
RelationshipFieldLabelClientComponent | RelationshipFieldLabelServerComponent
|
||||
>
|
||||
} & Admin['components']
|
||||
isSortable?: boolean
|
||||
} & Admin
|
||||
@@ -988,8 +1077,8 @@ export type RichTextField<
|
||||
> = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent
|
||||
Label?: CustomComponent
|
||||
} & Admin['components']
|
||||
} & Admin
|
||||
editor?:
|
||||
@@ -1015,6 +1104,7 @@ export type RichTextFieldClient<
|
||||
Error?: MappedComponent
|
||||
Label?: MappedComponent
|
||||
} & AdminClient['components']
|
||||
placeholder?: Record<string, string> | string
|
||||
} & AdminClient
|
||||
richTextComponentMap?: Map<string, any>
|
||||
} & FieldBaseClient &
|
||||
@@ -1024,8 +1114,8 @@ export type RichTextFieldClient<
|
||||
export type ArrayField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<ArrayFieldErrorClientComponent | ArrayFieldErrorServerComponent>
|
||||
Label?: CustomComponent<ArrayFieldLabelClientComponent | ArrayFieldLabelServerComponent>
|
||||
RowLabel?: RowLabelComponent
|
||||
} & Admin['components']
|
||||
initCollapsed?: boolean
|
||||
@@ -1070,8 +1160,8 @@ export type ArrayFieldClient = {
|
||||
export type RadioField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<RadioFieldErrorClientComponent | RadioFieldErrorServerComponent>
|
||||
Label?: CustomComponent<RadioFieldLabelClientComponent | RadioFieldLabelServerComponent>
|
||||
} & Admin['components']
|
||||
layout?: 'horizontal' | 'vertical'
|
||||
} & Admin
|
||||
@@ -1157,7 +1247,7 @@ export type ClientBlock = {
|
||||
export type BlockField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Error?: CustomComponent<BlockFieldErrorClientComponent | BlockFieldErrorServerComponent>
|
||||
} & Admin['components']
|
||||
initCollapsed?: boolean
|
||||
/**
|
||||
@@ -1189,8 +1279,8 @@ export type BlockFieldClient = {
|
||||
export type PointField = {
|
||||
admin?: {
|
||||
components?: {
|
||||
Error?: ErrorComponent
|
||||
Label?: LabelComponent
|
||||
Error?: CustomComponent<PointFieldErrorClientComponent | PointFieldErrorServerComponent>
|
||||
Label?: CustomComponent<PointFieldLabelClientComponent | PointFieldLabelServerComponent>
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
} & Admin['components']
|
||||
@@ -1260,6 +1350,28 @@ export type ClientField =
|
||||
| UIFieldClient
|
||||
| UploadFieldClient
|
||||
|
||||
export type ClientFieldProps =
|
||||
| ArrayFieldProps
|
||||
| BlockFieldProps
|
||||
| CheckboxFieldProps
|
||||
| CodeFieldProps
|
||||
| CollapsibleFieldProps
|
||||
| DateFieldProps
|
||||
| EmailFieldProps
|
||||
| GroupFieldProps
|
||||
| HiddenFieldProps
|
||||
| JSONFieldProps
|
||||
| NumberFieldProps
|
||||
| PointFieldProps
|
||||
| RadioFieldProps
|
||||
| RelationshipFieldProps
|
||||
| RichTextFieldProps
|
||||
| RowFieldProps
|
||||
| SelectFieldProps
|
||||
| TabsFieldProps
|
||||
| TextareaFieldProps
|
||||
| UploadFieldProps
|
||||
|
||||
type ExtractFieldTypes<T> = T extends { type: infer U } ? U : never
|
||||
|
||||
export type FieldTypes = ExtractFieldTypes<Field>
|
||||
@@ -1373,9 +1485,9 @@ export type FieldWithManyClient = RelationshipFieldClient | SelectFieldClient
|
||||
export type FieldWithMaxDepth = RelationshipField | UploadField
|
||||
export type FieldWithMaxDepthClient = RelationshipFieldClient | UploadFieldClient
|
||||
|
||||
export function fieldHasSubFields<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? FieldWithSubFieldsClient : FieldWithSubFields) {
|
||||
export function fieldHasSubFields<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? FieldWithSubFieldsClient : FieldWithSubFields) {
|
||||
return (
|
||||
field.type === 'group' ||
|
||||
field.type === 'array' ||
|
||||
@@ -1384,21 +1496,21 @@ export function fieldHasSubFields<T extends ClientField | Field>(
|
||||
)
|
||||
}
|
||||
|
||||
export function fieldIsArrayType<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? ArrayFieldClient : ArrayField) {
|
||||
export function fieldIsArrayType<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? ArrayFieldClient : ArrayField) {
|
||||
return field.type === 'array'
|
||||
}
|
||||
|
||||
export function fieldIsBlockType<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? BlockFieldClient : BlockField) {
|
||||
export function fieldIsBlockType<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? BlockFieldClient : BlockField) {
|
||||
return field.type === 'blocks'
|
||||
}
|
||||
|
||||
export function fieldIsGroupType<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? GroupFieldClient : GroupField) {
|
||||
export function fieldIsGroupType<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? GroupFieldClient : GroupField) {
|
||||
return field.type === 'group'
|
||||
}
|
||||
|
||||
@@ -1414,40 +1526,44 @@ export function optionIsValue(option: Option): option is string {
|
||||
return typeof option === 'string'
|
||||
}
|
||||
|
||||
export function fieldSupportsMany<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? FieldWithManyClient : FieldWithMany) {
|
||||
export function fieldSupportsMany<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? FieldWithManyClient : FieldWithMany) {
|
||||
return field.type === 'select' || field.type === 'relationship'
|
||||
}
|
||||
|
||||
export function fieldHasMaxDepth<T extends ClientField | Field>(
|
||||
field: T,
|
||||
): field is T & (T extends ClientField ? FieldWithMaxDepthClient : FieldWithMaxDepth) {
|
||||
export function fieldHasMaxDepth<TField extends ClientField | Field>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField ? FieldWithMaxDepthClient : FieldWithMaxDepth) {
|
||||
return (
|
||||
(field.type === 'upload' || field.type === 'relationship') && typeof field.maxDepth === 'number'
|
||||
)
|
||||
}
|
||||
|
||||
export function fieldIsPresentationalOnly<
|
||||
T extends ClientField | Field | TabAsField | TabAsFieldClient,
|
||||
>(field: T): field is T & (T extends ClientField | TabAsFieldClient ? UIFieldClient : UIField) {
|
||||
TField extends ClientField | Field | TabAsField | TabAsFieldClient,
|
||||
>(
|
||||
field: TField,
|
||||
): field is TField & (TField extends ClientField | TabAsFieldClient ? UIFieldClient : UIField) {
|
||||
return field.type === 'ui'
|
||||
}
|
||||
|
||||
export function fieldIsSidebar<T extends ClientField | Field | TabAsField | TabAsFieldClient>(
|
||||
field: T,
|
||||
): field is { admin: { position: 'sidebar' } } & T {
|
||||
export function fieldIsSidebar<TField extends ClientField | Field | TabAsField | TabAsFieldClient>(
|
||||
field: TField,
|
||||
): field is { admin: { position: 'sidebar' } } & TField {
|
||||
return 'admin' in field && 'position' in field.admin && field.admin.position === 'sidebar'
|
||||
}
|
||||
|
||||
export function fieldAffectsData<T extends ClientField | Field | TabAsField | TabAsFieldClient>(
|
||||
field: T,
|
||||
): field is T &
|
||||
(T extends ClientField | TabAsFieldClient ? FieldAffectingDataClient : FieldAffectingData) {
|
||||
export function fieldAffectsData<
|
||||
TField extends ClientField | Field | TabAsField | TabAsFieldClient,
|
||||
>(
|
||||
field: TField,
|
||||
): field is TField &
|
||||
(TField extends ClientField | TabAsFieldClient ? FieldAffectingDataClient : FieldAffectingData) {
|
||||
return 'name' in field && !fieldIsPresentationalOnly(field)
|
||||
}
|
||||
|
||||
export function tabHasName<T extends ClientTab | Tab>(tab: T): tab is NamedTab & T {
|
||||
export function tabHasName<TField extends ClientTab | Tab>(tab: TField): tab is NamedTab & TField {
|
||||
return 'name' in tab
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,137 @@ describe('configToJSONSchema', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle block fields with no blocks', async () => {
|
||||
// @ts-expect-error
|
||||
const config: Config = {
|
||||
collections: [
|
||||
{
|
||||
slug: 'test',
|
||||
fields: [
|
||||
{
|
||||
name: 'blockField',
|
||||
type: 'blocks',
|
||||
blocks: [],
|
||||
},
|
||||
{
|
||||
name: 'blockFieldRequired',
|
||||
type: 'blocks',
|
||||
blocks: [],
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'blockFieldWithFields',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'test',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blockFieldWithFieldsRequired',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'test',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
timestamps: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const sanitizedConfig = await sanitizeConfig(config)
|
||||
const schema = configToJSONSchema(sanitizedConfig, 'text')
|
||||
|
||||
expect(schema?.definitions?.test).toStrictEqual({
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
blockField: {
|
||||
type: ['array', 'null'],
|
||||
items: {},
|
||||
},
|
||||
blockFieldRequired: {
|
||||
type: 'array',
|
||||
items: {},
|
||||
},
|
||||
blockFieldWithFields: {
|
||||
type: ['array', 'null'],
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
blockName: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
blockType: {
|
||||
const: 'test',
|
||||
},
|
||||
field: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
},
|
||||
required: ['blockType'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
blockFieldWithFieldsRequired: {
|
||||
type: ['array', 'null'],
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
id: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
blockName: {
|
||||
type: ['string', 'null'],
|
||||
},
|
||||
blockType: {
|
||||
const: 'test',
|
||||
},
|
||||
field: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
required: ['blockType', 'field'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['id', 'blockFieldRequired'],
|
||||
title: 'Test',
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle tabs and named tabs with required fields', async () => {
|
||||
// @ts-expect-error
|
||||
const config: Config = {
|
||||
|
||||
@@ -396,40 +396,47 @@ export function fieldsToJSONSchema(
|
||||
}
|
||||
|
||||
case 'blocks': {
|
||||
// Check for a case where no blocks are provided.
|
||||
// We need to generate an empty array for this case, note that JSON schema 4 doesn't support empty arrays
|
||||
// so the best we can get is `unknown[]`
|
||||
const hasBlocks = Boolean(field.blocks.length)
|
||||
|
||||
fieldSchema = {
|
||||
type: withNullableJSONSchemaType('array', isRequired),
|
||||
items: {
|
||||
oneOf: field.blocks.map((block) => {
|
||||
const blockFieldSchemas = fieldsToJSONSchema(
|
||||
collectionIDFieldTypes,
|
||||
block.fields,
|
||||
interfaceNameDefinitions,
|
||||
config,
|
||||
)
|
||||
items: hasBlocks
|
||||
? {
|
||||
oneOf: field.blocks.map((block) => {
|
||||
const blockFieldSchemas = fieldsToJSONSchema(
|
||||
collectionIDFieldTypes,
|
||||
block.fields,
|
||||
interfaceNameDefinitions,
|
||||
config,
|
||||
)
|
||||
|
||||
const blockSchema: JSONSchema4 = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...blockFieldSchemas.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
},
|
||||
required: ['blockType', ...blockFieldSchemas.required],
|
||||
const blockSchema: JSONSchema4 = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...blockFieldSchemas.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
},
|
||||
required: ['blockType', ...blockFieldSchemas.required],
|
||||
}
|
||||
|
||||
if (block.interfaceName) {
|
||||
interfaceNameDefinitions.set(block.interfaceName, blockSchema)
|
||||
|
||||
return {
|
||||
$ref: `#/definitions/${block.interfaceName}`,
|
||||
}
|
||||
}
|
||||
|
||||
return blockSchema
|
||||
}),
|
||||
}
|
||||
|
||||
if (block.interfaceName) {
|
||||
interfaceNameDefinitions.set(block.interfaceName, blockSchema)
|
||||
|
||||
return {
|
||||
$ref: `#/definitions/${block.interfaceName}`,
|
||||
}
|
||||
}
|
||||
|
||||
return blockSchema
|
||||
}),
|
||||
},
|
||||
: {},
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ClientTab } from '../admin/fields/Tabs.js'
|
||||
import type { ClientField } from '../fields/config/client.js'
|
||||
import type {
|
||||
Field,
|
||||
@@ -14,13 +15,12 @@ import {
|
||||
fieldIsPresentationalOnly,
|
||||
tabHasName,
|
||||
} from '../fields/config/types.js'
|
||||
import { ClientTab } from '../admin/fields/Tabs.js'
|
||||
|
||||
type FlattenedField<T> = T extends ClientField
|
||||
type FlattenedField<TField> = TField extends ClientField
|
||||
? FieldAffectingDataClient | FieldPresentationalOnlyClient
|
||||
: FieldAffectingData | FieldPresentationalOnly
|
||||
|
||||
type TabType<T> = T extends ClientField ? ClientTab : Tab
|
||||
type TabType<TField> = TField extends ClientField ? ClientTab : Tab
|
||||
|
||||
/**
|
||||
* Flattens a collection's fields into a single array of fields, as long
|
||||
@@ -29,27 +29,30 @@ type TabType<T> = T extends ClientField ? ClientTab : Tab
|
||||
* @param fields
|
||||
* @param keepPresentationalFields if true, will skip flattening fields that are presentational only
|
||||
*/
|
||||
function flattenFields<T extends ClientField | Field>(
|
||||
fields: T[],
|
||||
function flattenFields<TField extends ClientField | Field>(
|
||||
fields: TField[],
|
||||
keepPresentationalFields?: boolean,
|
||||
): FlattenedField<T>[] {
|
||||
return fields.reduce<FlattenedField<T>[]>((fieldsToUse, field) => {
|
||||
): FlattenedField<TField>[] {
|
||||
return fields.reduce<FlattenedField<TField>[]>((fieldsToUse, field) => {
|
||||
if (fieldAffectsData(field) || (keepPresentationalFields && fieldIsPresentationalOnly(field))) {
|
||||
return [...fieldsToUse, field as FlattenedField<T>]
|
||||
return [...fieldsToUse, field as FlattenedField<TField>]
|
||||
}
|
||||
|
||||
if (fieldHasSubFields(field)) {
|
||||
return [...fieldsToUse, ...flattenFields(field.fields as T[], keepPresentationalFields)]
|
||||
return [...fieldsToUse, ...flattenFields(field.fields as TField[], keepPresentationalFields)]
|
||||
}
|
||||
|
||||
if (field.type === 'tabs' && 'tabs' in field) {
|
||||
return [
|
||||
...fieldsToUse,
|
||||
...field.tabs.reduce<FlattenedField<T>[]>((tabFields, tab: TabType<T>) => {
|
||||
...field.tabs.reduce<FlattenedField<TField>[]>((tabFields, tab: TabType<TField>) => {
|
||||
if (tabHasName(tab)) {
|
||||
return [...tabFields, { ...tab, type: 'tab' } as unknown as FlattenedField<T>]
|
||||
return [...tabFields, { ...tab, type: 'tab' } as unknown as FlattenedField<TField>]
|
||||
} else {
|
||||
return [...tabFields, ...flattenFields(tab.fields as T[], keepPresentationalFields)]
|
||||
return [
|
||||
...tabFields,
|
||||
...flattenFields(tab.fields as TField[], keepPresentationalFields),
|
||||
]
|
||||
}
|
||||
}, []),
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -88,7 +88,7 @@ export const getFields = ({ collection, prefix }: Args): Field[] => {
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
...(existingSizeURLField || {}),
|
||||
...(existingSizeURLField || ({} as any)),
|
||||
...baseURLField,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -108,7 +108,7 @@ export const getFields = ({
|
||||
fields: [
|
||||
...(adapter.fields || []),
|
||||
{
|
||||
...(existingSizeURLField || {}),
|
||||
...(existingSizeURLField || ({} as any)),
|
||||
...baseURLField,
|
||||
hooks: {
|
||||
afterRead: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-form-builder",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Form builder plugin for Payload CMS",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-nested-docs",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The official Nested Docs plugin for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-redirects",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Redirects plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-relationship-object-ids",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "A Payload plugin to store all relationship IDs as ObjectIDs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-search",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Search plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-seo",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "SEO plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -24,7 +24,7 @@ import { LengthIndicator } from '../../ui/LengthIndicator.js'
|
||||
const { maxLength, minLength } = defaults.description
|
||||
|
||||
type MetaDescriptionProps = {
|
||||
hasGenerateDescriptionFn: boolean
|
||||
readonly hasGenerateDescriptionFn: boolean
|
||||
} & TextareaFieldProps
|
||||
|
||||
export const MetaDescriptionComponent: React.FC<MetaDescriptionProps> = (props) => {
|
||||
@@ -58,9 +58,16 @@ export const MetaDescriptionComponent: React.FC<MetaDescriptionProps> = (props)
|
||||
|
||||
const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
id: docInfo.id,
|
||||
slug: docInfo.slug,
|
||||
doc: getData(),
|
||||
docPermissions: docInfo.docPermissions,
|
||||
hasPublishPermission: docInfo.hasPublishPermission,
|
||||
hasSavePermission: docInfo.hasSavePermission,
|
||||
initialData: docInfo.initialData,
|
||||
initialState: docInfo.initialState,
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
title: docInfo.title,
|
||||
} satisfies Omit<Parameters<GenerateDescription>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
@@ -87,7 +94,7 @@ export const MetaDescriptionComponent: React.FC<MetaDescriptionProps> = (props)
|
||||
}}
|
||||
>
|
||||
<div className="plugin-seo__field">
|
||||
<FieldLabel Label={Label} label={label} {...(labelProps || {})} />
|
||||
<FieldLabel Label={Label} field={null} label={label} {...(labelProps || {})} />
|
||||
{hasGenerateDescriptionFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
|
||||
@@ -21,7 +21,7 @@ import type { GenerateImage } from '../../types.js'
|
||||
import { Pill } from '../../ui/Pill.js'
|
||||
|
||||
type MetaImageProps = {
|
||||
hasGenerateImageFn: boolean
|
||||
readonly hasGenerateImageFn: boolean
|
||||
} & UploadFieldProps
|
||||
|
||||
export const MetaImageComponent: React.FC<MetaImageProps> = (props) => {
|
||||
@@ -54,9 +54,16 @@ export const MetaImageComponent: React.FC<MetaImageProps> = (props) => {
|
||||
|
||||
const genImageResponse = await fetch('/api/plugin-seo/generate-image', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
id: docInfo.id,
|
||||
slug: docInfo.slug,
|
||||
doc: getData(),
|
||||
docPermissions: docInfo.docPermissions,
|
||||
hasPublishPermission: docInfo.hasPublishPermission,
|
||||
hasSavePermission: docInfo.hasSavePermission,
|
||||
initialData: docInfo.initialData,
|
||||
initialState: docInfo.initialState,
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
title: docInfo.title,
|
||||
} satisfies Omit<Parameters<GenerateImage>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
@@ -91,7 +98,7 @@ export const MetaImageComponent: React.FC<MetaImageProps> = (props) => {
|
||||
}}
|
||||
>
|
||||
<div className="plugin-seo__field">
|
||||
<FieldLabel Label={Label} label={label} {...(labelProps || {})} />
|
||||
<FieldLabel Label={Label} field={null} label={label} {...(labelProps || {})} />
|
||||
{hasGenerateImageFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
|
||||
@@ -25,7 +25,7 @@ import '../index.scss'
|
||||
const { maxLength, minLength } = defaults.title
|
||||
|
||||
type MetaTitleProps = {
|
||||
hasGenerateTitleFn: boolean
|
||||
readonly hasGenerateTitleFn: boolean
|
||||
} & TextFieldProps
|
||||
|
||||
export const MetaTitleComponent: React.FC<MetaTitleProps> = (props) => {
|
||||
@@ -59,9 +59,16 @@ export const MetaTitleComponent: React.FC<MetaTitleProps> = (props) => {
|
||||
|
||||
const genTitleResponse = await fetch('/api/plugin-seo/generate-title', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
id: docInfo.id,
|
||||
slug: docInfo.slug,
|
||||
doc: getData(),
|
||||
docPermissions: docInfo.docPermissions,
|
||||
hasPublishPermission: docInfo.hasPublishPermission,
|
||||
hasSavePermission: docInfo.hasSavePermission,
|
||||
initialData: docInfo.initialData,
|
||||
initialState: docInfo.initialState,
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
title: docInfo.title,
|
||||
} satisfies Omit<Parameters<GenerateTitle>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
@@ -88,7 +95,7 @@ export const MetaTitleComponent: React.FC<MetaTitleProps> = (props) => {
|
||||
}}
|
||||
>
|
||||
<div className="plugin-seo__field">
|
||||
<FieldLabel Label={Label} label={label} {...(labelProps || {})} />
|
||||
<FieldLabel Label={Label} field={null} label={label} {...(labelProps || {})} />
|
||||
{hasGenerateTitleFn && (
|
||||
<React.Fragment>
|
||||
—
|
||||
|
||||
@@ -15,16 +15,18 @@ import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../tran
|
||||
import type { GenerateURL } from '../../types.js'
|
||||
|
||||
type PreviewProps = {
|
||||
descriptionPath?: string
|
||||
hasGenerateURLFn: boolean
|
||||
titlePath?: string
|
||||
readonly descriptionPath?: string
|
||||
readonly hasGenerateURLFn: boolean
|
||||
readonly titlePath?: string
|
||||
} & UIField
|
||||
|
||||
export const PreviewComponent: React.FC<PreviewProps> = ({
|
||||
descriptionPath: descriptionPathFromContext,
|
||||
hasGenerateURLFn,
|
||||
titlePath: titlePathFromContext,
|
||||
}) => {
|
||||
export const PreviewComponent: React.FC<PreviewProps> = (props) => {
|
||||
const {
|
||||
descriptionPath: descriptionPathFromContext,
|
||||
hasGenerateURLFn,
|
||||
titlePath: titlePathFromContext,
|
||||
} = props
|
||||
|
||||
const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>()
|
||||
|
||||
const locale = useLocale()
|
||||
@@ -46,9 +48,15 @@ export const PreviewComponent: React.FC<PreviewProps> = ({
|
||||
const getHref = async () => {
|
||||
const genURLResponse = await fetch('/api/plugin-seo/generate-url', {
|
||||
body: JSON.stringify({
|
||||
...docInfo,
|
||||
doc: { ...getData() },
|
||||
id: docInfo.id,
|
||||
doc: getData(),
|
||||
docPermissions: docInfo.docPermissions,
|
||||
hasPublishPermission: docInfo.hasPublishPermission,
|
||||
hasSavePermission: docInfo.hasSavePermission,
|
||||
initialData: docInfo.initialData,
|
||||
initialState: docInfo.initialState,
|
||||
locale: typeof locale === 'object' ? locale?.code : locale,
|
||||
title: docInfo.title,
|
||||
} satisfies Omit<Parameters<GenerateURL>[0], 'req'>),
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
import type { DocumentInfoContext } from '@payloadcms/ui'
|
||||
import type { Field, PayloadRequest, TextField, TextareaField, UploadField } from 'payload'
|
||||
|
||||
export type PartialDocumentInfoContext = Pick<
|
||||
DocumentInfoContext,
|
||||
| 'docPermissions'
|
||||
| 'hasPublishPermission'
|
||||
| 'hasSavePermission'
|
||||
| 'id'
|
||||
| 'initialData'
|
||||
| 'initialState'
|
||||
| 'preferencesKey'
|
||||
| 'publishedDoc'
|
||||
| 'slug'
|
||||
| 'title'
|
||||
| 'versionsCount'
|
||||
>
|
||||
|
||||
export type GenerateTitle<T = any> = (
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateDescription<T = any> = (
|
||||
@@ -10,15 +25,15 @@ export type GenerateDescription<T = any> = (
|
||||
doc: T
|
||||
locale?: string
|
||||
req: PayloadRequest
|
||||
} & DocumentInfoContext,
|
||||
} & PartialDocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateImage<T = any> = (
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type GenerateURL<T = any> = (
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & DocumentInfoContext,
|
||||
args: { doc: T; locale?: string; req: PayloadRequest } & PartialDocumentInfoContext,
|
||||
) => Promise<string> | string
|
||||
|
||||
export type SEOPluginConfig = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-stripe",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "Stripe plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
36
packages/richtext-lexical/babel.config.cjs
Normal file
36
packages/richtext-lexical/babel.config.cjs
Normal file
@@ -0,0 +1,36 @@
|
||||
const fs = require('fs')
|
||||
|
||||
// Plugin options can be found here: https://github.com/facebook/react/blob/main/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts#L38
|
||||
const ReactCompilerConfig = {
|
||||
sources: (filename) => {
|
||||
const isInNodeModules = filename.includes('node_modules')
|
||||
if (isInNodeModules || ( !filename.endsWith('.tsx') && !filename.endsWith('.jsx') && !filename.endsWith('.js'))) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only compile files with 'use client' directives. We do not want to
|
||||
// accidentally compile React Server Components
|
||||
const file = fs.readFileSync(filename, 'utf8')
|
||||
if (file.includes("'use client'")) {
|
||||
return true
|
||||
}
|
||||
console.log('React compiler - skipping file: ' + filename)
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = function (api) {
|
||||
api.cache(false)
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
['babel-plugin-react-compiler', ReactCompilerConfig], // must run first!
|
||||
/* [
|
||||
'babel-plugin-transform-remove-imports',
|
||||
{
|
||||
test: '\\.(scss|css)$',
|
||||
},
|
||||
],*/
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -24,15 +24,20 @@ async function build() {
|
||||
entryPoints: ['src/exports/client/index.ts'],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
outdir: 'dist/field',
|
||||
outdir: 'dist/bundled_scss',
|
||||
loader: { '.svg': 'dataurl' },
|
||||
packages: 'external',
|
||||
//external: ['*.svg'],
|
||||
plugins: [sassPlugin({ css: 'external' })],
|
||||
})
|
||||
|
||||
//create empty dist/exports/client_optimized dir
|
||||
fs.mkdirSync('dist/exports/client_optimized')
|
||||
|
||||
try {
|
||||
fs.renameSync('dist/field/index.css', 'dist/exports/client/bundled.css')
|
||||
fs.renameSync('dist/bundled_scss/index.css', 'dist/field/bundled.css')
|
||||
fs.copyFileSync('dist/field/bundled.css', 'dist/exports/client_optimized/bundled.css')
|
||||
fs.rmSync('dist/bundled_scss', { recursive: true })
|
||||
} catch (err) {
|
||||
console.error(`Error while renaming index.css: ${err}`)
|
||||
throw err
|
||||
@@ -42,11 +47,11 @@ async function build() {
|
||||
|
||||
// Bundle `client.ts`
|
||||
const resultClient = await esbuild.build({
|
||||
entryPoints: ['src/exports/client/index.ts'],
|
||||
entryPoints: ['dist/exports/client/index.js'],
|
||||
bundle: true,
|
||||
platform: 'browser',
|
||||
format: 'esm',
|
||||
outdir: 'dist/exports/client',
|
||||
outdir: 'dist/exports/client_optimized',
|
||||
//outfile: 'index.js',
|
||||
// IMPORTANT: splitting the client bundle means that the `use client` directive will be lost for every chunk
|
||||
splitting: true,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import lexical from '@lexical/eslint-plugin'
|
||||
import { rootEslintConfig, rootParserOptions } from '../../eslint.config.js'
|
||||
import reactCompiler from 'eslint-plugin-react-compiler'
|
||||
const { rules } = reactCompiler
|
||||
|
||||
/** @typedef {import('eslint').Linter.FlatConfig} */
|
||||
let FlatConfig
|
||||
@@ -20,6 +22,16 @@ export const index = [
|
||||
},
|
||||
rules: lexical.configs.recommended.rules,
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
'react-compiler': {
|
||||
rules,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'react-compiler/react-compiler': 'error',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export default index
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "3.0.0-beta.85",
|
||||
"version": "3.0.0-beta.87",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
@@ -36,11 +36,14 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm copyfiles && pnpm build:types && pnpm build:swc && pnpm build:esbuild",
|
||||
"build": "pnpm build:reactcompiler",
|
||||
"build:babel": "rm -rf dist_optimized && babel dist --out-dir dist_optimized --source-maps --extensions .ts,.js,.tsx,.jsx,.cjs,.mjs && rm -rf dist && mv dist_optimized dist",
|
||||
"build:clean": "find . \\( -type d \\( -name build -o -name dist -o -name .cache \\) -o -type f -name tsconfig.tsbuildinfo \\) -exec rm -rf {} + && pnpm build",
|
||||
"build:esbuild": "node bundle.js",
|
||||
"build:esbuild": "node bundle.js && rm -rf dist/exports/client && mv dist/exports/client_optimized dist/exports/client",
|
||||
"build:reactcompiler": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && pnpm build:esbuild && pnpm build:types",
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
||||
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
||||
"build_without_reactcompiler": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm copyfiles && pnpm build:types && pnpm build:swc && pnpm build:esbuild && rm -rf dist/exports/client && mv dist/exports/client_unoptimized dist/exports/client",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
||||
"prepublishOnly": "pnpm clean && pnpm turbo build",
|
||||
@@ -64,6 +67,11 @@
|
||||
"uuid": "10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.24.5",
|
||||
"@babel/core": "^7.24.5",
|
||||
"@babel/preset-env": "^7.24.5",
|
||||
"@babel/preset-react": "^7.24.1",
|
||||
"@babel/preset-typescript": "^7.24.1",
|
||||
"@lexical/eslint-plugin": "0.17.0",
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@payloadcms/next": "workspace:*",
|
||||
@@ -73,8 +81,11 @@
|
||||
"@types/node": "20.12.5",
|
||||
"@types/react": "npm:types-react@19.0.0-rc.0",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.0",
|
||||
"babel-plugin-react-compiler": "0.0.0-experimental-1cd8995-20240814",
|
||||
"babel-plugin-transform-remove-imports": "^1.8.0",
|
||||
"esbuild": "0.23.0",
|
||||
"esbuild-sass-plugin": "3.3.1",
|
||||
"eslint-plugin-react-compiler": "0.0.0-experimental-d0e920e-20240815",
|
||||
"payload": "workspace:*",
|
||||
"swc-plugin-transform-remove-imports": "1.15.0"
|
||||
},
|
||||
|
||||
@@ -18,8 +18,8 @@ import { getEnabledNodes } from '../lexical/nodes/index.js'
|
||||
|
||||
export const RichTextCell: React.FC<
|
||||
{
|
||||
admin?: LexicalFieldAdminProps
|
||||
lexicalEditorConfig: LexicalEditorConfig
|
||||
readonly admin?: LexicalFieldAdminProps
|
||||
readonly lexicalEditorConfig: LexicalEditorConfig
|
||||
} & CellComponentProps<RichTextFieldClient>
|
||||
> = (props) => {
|
||||
const {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { ToolbarGroup, ToolbarGroupItem } from '../../toolbars/types.js'
|
||||
|
||||
import { AlignLeftIcon } from '../../../lexical/ui/icons/AlignLeft/index.js'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { ClientBlock, ClientField, CollapsedPreferences, FormState } from 'payload'
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { Data, FormState } from 'payload'
|
||||
import type React from 'react'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { FormState } from 'payload'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { EditorConfig, LexicalEditor, LexicalNode } from 'lexical'
|
||||
|
||||
import ObjectID from 'bson-objectid'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type {
|
||||
EditorConfig,
|
||||
LexicalEditor,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { LexicalCommand } from 'lexical'
|
||||
|
||||
import { createCommand } from 'lexical'
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
'use client'
|
||||
|
||||
import type { TableCellNode, TableRowNode } from '@lexical/table'
|
||||
import type { EditorConfig, NodeKey } from 'lexical'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
// Copied & modified from https://github.com/lodash/lodash/blob/main/src/debounce.ts
|
||||
/*
|
||||
The MIT License
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import { useMemo, useRef } from 'react'
|
||||
|
||||
import debounce from './debounce.js'
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import type { TableCellNode, TableRowNode } from '@lexical/table'
|
||||
import type { EditorConfig, NodeKey } from 'lexical'
|
||||
import type { JSX } from 'react'
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import {
|
||||
$getTableColumnIndexFromTableCellNode,
|
||||
$getTableRowIndexFromTableCellNode,
|
||||
$insertTableColumn__EXPERIMENTAL,
|
||||
$insertTableRow__EXPERIMENTAL,
|
||||
$isTableCellNode,
|
||||
$isTableNode,
|
||||
TableNode,
|
||||
} from '@lexical/table'
|
||||
import { $findMatchingParent, mergeRegister } from '@lexical/utils'
|
||||
import { $getNearestNodeFromDOMNode } from 'lexical'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import * as React from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'
|
||||
import { useDebounce } from '../../client/utils/useDebounce.js'
|
||||
|
||||
const BUTTON_WIDTH_PX = 20
|
||||
|
||||
function TableHoverActionsContainer({ anchorElem }: { anchorElem: HTMLElement }): JSX.Element {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const editorConfig = useEditorConfigContext()
|
||||
const [isShownRow, setShownRow] = useState<boolean>(false)
|
||||
const [isShownColumn, setShownColumn] = useState<boolean>(false)
|
||||
const [shouldListenMouseMove, setShouldListenMouseMove] = useState<boolean>(false)
|
||||
const [position, setPosition] = useState({})
|
||||
const codeSetRef = useRef<Set<NodeKey>>(new Set())
|
||||
const tableDOMNodeRef = useRef<HTMLElement | null>(null)
|
||||
|
||||
const debouncedOnMouseMove = useDebounce(
|
||||
(event: MouseEvent) => {
|
||||
const { isOutside, tableDOMNode } = getMouseInfo(event, editorConfig.editorConfig?.lexical)
|
||||
|
||||
if (isOutside) {
|
||||
setShownRow(false)
|
||||
setShownColumn(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (!tableDOMNode) {
|
||||
return
|
||||
}
|
||||
|
||||
tableDOMNodeRef.current = tableDOMNode
|
||||
|
||||
let hoveredRowNode: TableCellNode | null = null
|
||||
let hoveredColumnNode: TableCellNode | null = null
|
||||
let tableDOMElement: HTMLElement | null = null
|
||||
|
||||
editor.update(() => {
|
||||
const maybeTableCell = $getNearestNodeFromDOMNode(tableDOMNode)
|
||||
|
||||
if ($isTableCellNode(maybeTableCell)) {
|
||||
const table = $findMatchingParent(maybeTableCell, (node) => $isTableNode(node))
|
||||
if (!$isTableNode(table)) {
|
||||
return
|
||||
}
|
||||
|
||||
tableDOMElement = editor.getElementByKey(table?.getKey())
|
||||
|
||||
if (tableDOMElement) {
|
||||
const rowCount = table.getChildrenSize()
|
||||
const colCount =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
((table as TableNode).getChildAtIndex(0) as TableRowNode)?.getChildrenSize()
|
||||
|
||||
const rowIndex = $getTableRowIndexFromTableCellNode(maybeTableCell)
|
||||
const colIndex = $getTableColumnIndexFromTableCellNode(maybeTableCell)
|
||||
|
||||
if (rowIndex === rowCount - 1) {
|
||||
hoveredRowNode = maybeTableCell
|
||||
} else if (colIndex === colCount - 1) {
|
||||
hoveredColumnNode = maybeTableCell
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (tableDOMElement) {
|
||||
const {
|
||||
bottom: tableElemBottom,
|
||||
height: tableElemHeight,
|
||||
right: tableElemRight,
|
||||
width: tableElemWidth,
|
||||
x: tableElemX,
|
||||
y: tableElemY,
|
||||
} = (tableDOMElement as HTMLTableElement).getBoundingClientRect()
|
||||
|
||||
const { left: editorElemLeft, y: editorElemY } = anchorElem.getBoundingClientRect()
|
||||
|
||||
if (hoveredRowNode) {
|
||||
setShownColumn(false)
|
||||
setShownRow(true)
|
||||
setPosition({
|
||||
height: BUTTON_WIDTH_PX,
|
||||
left: tableElemX - editorElemLeft,
|
||||
top: tableElemBottom - editorElemY + 5,
|
||||
width: tableElemWidth,
|
||||
})
|
||||
} else if (hoveredColumnNode) {
|
||||
setShownColumn(true)
|
||||
setShownRow(false)
|
||||
setPosition({
|
||||
height: tableElemHeight,
|
||||
left: tableElemRight - editorElemLeft + 5,
|
||||
top: tableElemY - editorElemY,
|
||||
width: BUTTON_WIDTH_PX,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
50,
|
||||
250,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldListenMouseMove) {
|
||||
return
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', debouncedOnMouseMove)
|
||||
|
||||
return () => {
|
||||
setShownRow(false)
|
||||
setShownColumn(false)
|
||||
|
||||
document.removeEventListener('mousemove', debouncedOnMouseMove)
|
||||
}
|
||||
}, [shouldListenMouseMove, debouncedOnMouseMove])
|
||||
|
||||
useEffect(() => {
|
||||
return mergeRegister(
|
||||
editor.registerMutationListener(
|
||||
TableNode,
|
||||
(mutations) => {
|
||||
editor.getEditorState().read(() => {
|
||||
for (const [key, type] of mutations) {
|
||||
switch (type) {
|
||||
case 'created':
|
||||
codeSetRef.current.add(key)
|
||||
setShouldListenMouseMove(codeSetRef.current.size > 0)
|
||||
break
|
||||
|
||||
case 'destroyed':
|
||||
codeSetRef.current.delete(key)
|
||||
setShouldListenMouseMove(codeSetRef.current.size > 0)
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
{ skipInitialization: false },
|
||||
),
|
||||
)
|
||||
}, [editor])
|
||||
|
||||
const insertAction = (insertRow: boolean) => {
|
||||
editor.update(() => {
|
||||
if (tableDOMNodeRef.current) {
|
||||
const maybeTableNode = $getNearestNodeFromDOMNode(tableDOMNodeRef.current)
|
||||
maybeTableNode?.selectEnd()
|
||||
if (insertRow) {
|
||||
$insertTableRow__EXPERIMENTAL()
|
||||
setShownRow(false)
|
||||
} else {
|
||||
$insertTableColumn__EXPERIMENTAL()
|
||||
setShownColumn(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isShownRow && (
|
||||
<button
|
||||
className={editorConfig.editorConfig.lexical.theme.tableAddRows}
|
||||
onClick={() => insertAction(true)}
|
||||
style={{ ...position }}
|
||||
/>
|
||||
)}
|
||||
{isShownColumn && (
|
||||
<button
|
||||
className={editorConfig.editorConfig.lexical.theme.tableAddColumns}
|
||||
onClick={() => insertAction(false)}
|
||||
style={{ ...position }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function getMouseInfo(
|
||||
event: MouseEvent,
|
||||
editorConfig: EditorConfig,
|
||||
): {
|
||||
isOutside: boolean
|
||||
tableDOMNode: HTMLElement | null
|
||||
} {
|
||||
const target = event.target
|
||||
|
||||
if (target && target instanceof HTMLElement) {
|
||||
const tableDOMNode = target.closest<HTMLElement>(
|
||||
`td.${editorConfig.theme.tableCell}, th.${editorConfig.theme.tableCell}`,
|
||||
)
|
||||
|
||||
const isOutside = !(
|
||||
tableDOMNode ||
|
||||
target.closest<HTMLElement>(`button.${editorConfig.theme.tableAddRows}`) ||
|
||||
target.closest<HTMLElement>(`button.${editorConfig.theme.tableAddColumns}`) ||
|
||||
target.closest<HTMLElement>(`div.${editorConfig.theme.tableCellResizer}`)
|
||||
)
|
||||
|
||||
return { isOutside, tableDOMNode }
|
||||
} else {
|
||||
return { isOutside: true, tableDOMNode: null }
|
||||
}
|
||||
}
|
||||
|
||||
export function TableHoverActionsPlugin({
|
||||
anchorElem = document.body,
|
||||
}: {
|
||||
anchorElem?: HTMLElement
|
||||
}): React.ReactPortal | null {
|
||||
return createPortal(<TableHoverActionsContainer anchorElem={anchorElem} />, anchorElem)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { ToolbarGroup, ToolbarGroupItem } from '../../toolbars/types.js'
|
||||
|
||||
export const toolbarFormatGroupWithItems = (items: ToolbarGroupItem[]): ToolbarGroup => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { DOMConversionOutput, LexicalNode, SerializedLexicalNode } from 'lexical'
|
||||
|
||||
import { $applyNodeReplacement } from 'lexical'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { ToolbarGroup, ToolbarGroupItem } from '../../toolbars/types.js'
|
||||
|
||||
export const toolbarIndentGroupWithItems = (items: ToolbarGroupItem[]): ToolbarGroup => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { LexicalCommand } from 'lexical'
|
||||
|
||||
import { createCommand } from 'lexical'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user