Compare commits

..

9 Commits

Author SHA1 Message Date
Paul Popus
c2cd6bbaec fix test error 2024-07-29 17:04:22 -04:00
Paul Popus
b2657ed12b fix tests 2024-07-29 14:02:28 -04:00
Paul Popus
0851ef99da update tests 2024-07-29 13:31:22 -04:00
Paul Popus
3c483ab57a update tests 2024-07-29 12:35:11 -04:00
Paul Popus
9bdbbb674f capitalise letters 2024-07-29 10:58:20 -04:00
Paul Popus
eb191f335b dont uppercase 2024-07-26 13:52:32 -04:00
Paul Popus
02bb176890 dont capitalise 2024-07-26 13:45:18 -04:00
Paul Popus
082c6ef44a add test and cleanup 2024-07-25 18:53:05 -04:00
Paul Popus
f93cdf9364 feat: format the error for field schema 2024-07-25 18:13:27 -04:00
253 changed files with 2484 additions and 2684 deletions

View File

@@ -196,7 +196,6 @@ jobs:
- postgres-custom-schema
- postgres-uuid
- supabase
- sqlite
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres

View File

@@ -38,7 +38,6 @@ jobs:
db-\*
db-mongodb
db-postgres
db-sqlite
email-nodemailer
eslint
graphql

View File

@@ -266,10 +266,12 @@ export const myField: Field = {
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
Custom Label Components receive all [Field Component](#the-field-component) props, plus the following props:
All Label Components receive the following props:
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`label`** | Label value provided in field, it can be used with i18n. |
| **`required`** | The `admin.required` property defined in the [Field Config](../fields/overview). |
| **`schemaPath`** | The path to the field in the schema. Similar to `path`, but without dynamic indices. |
<Banner type="success">
@@ -277,36 +279,6 @@ Custom Label Components receive all [Field Component](#the-field-component) prop
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### 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`.
```tsx
import type {
ArrayFieldLabelComponent,
BlocksFieldLabelComponent,
CheckboxFieldLabelComponent,
CodeFieldLabelComponent,
CollapsibleFieldLabelComponent,
DateFieldLabelComponent,
EmailFieldLabelComponent,
GroupFieldLabelComponent,
HiddenFieldLabelComponent,
JSONFieldLabelComponent,
NumberFieldLabelComponent,
PointFieldLabelComponent,
RadioFieldLabelComponent,
RelationshipFieldLabelComponent,
RichTextFieldLabelComponent,
RowFieldLabelComponent,
SelectFieldLabelComponent,
TabsFieldLabelComponent,
TextFieldLabelComponent,
TextareaFieldLabelComponent,
UploadFieldLabelComponent
} from 'payload'
```
### The Error Component
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
@@ -329,7 +301,7 @@ export const myField: Field = {
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
Custom Error Components receive all [Field Component](#the-field-component) props, plus the following props:
All Error Components receive the following props:
| Property | Description |
| --------------- | ------------------------------------------------------------- |
@@ -340,36 +312,6 @@ Custom Error Components receive all [Field Component](#the-field-component) prop
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### 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`.
```tsx
import type {
ArrayFieldErrorComponent,
BlocksFieldErrorComponent,
CheckboxFieldErrorComponent,
CodeFieldErrorComponent,
CollapsibleFieldErrorComponent,
DateFieldErrorComponent,
EmailFieldErrorComponent,
GroupFieldErrorComponent,
HiddenFieldErrorComponent,
JSONFieldErrorComponent,
NumberFieldErrorComponent,
PointFieldErrorComponent,
RadioFieldErrorComponent,
RelationshipFieldErrorComponent,
RichTextFieldErrorComponent,
RowFieldErrorComponent,
SelectFieldErrorComponent,
TabsFieldErrorComponent,
TextFieldErrorComponent,
TextareaFieldErrorComponent,
UploadFieldErrorComponent
} from 'payload'
```
### The Description Property
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
@@ -464,7 +406,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
_For details on how to build a Custom Description, see [Building Custom Components](./components#building-custom-components)._
Custom Description Components receive all [Field Component](#the-field-component) props, plus the following props:
All Description Components receive the following props:
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
@@ -475,36 +417,6 @@ Custom Description Components receive all [Field Component](#the-field-component
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### 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`.
```tsx
import type {
ArrayFieldDescriptionComponent,
BlocksFieldDescriptionComponent,
CheckboxFieldDescriptionComponent,
CodeFieldDescriptionComponent,
CollapsibleFieldDescriptionComponent,
DateFieldDescriptionComponent,
EmailFieldDescriptionComponent,
GroupFieldDescriptionComponent,
HiddenFieldDescriptionComponent,
JSONFieldDescriptionComponent,
NumberFieldDescriptionComponent,
PointFieldDescriptionComponent,
RadioFieldDescriptionComponent,
RelationshipFieldDescriptionComponent,
RichTextFieldDescriptionComponent,
RowFieldDescriptionComponent,
SelectFieldDescriptionComponent,
TabsFieldDescriptionComponent,
TextFieldDescriptionComponent,
TextareaFieldDescriptionComponent,
UploadFieldDescriptionComponent
} from 'payload'
```
### afterInput and beforeInput
With these properties you can add multiple components _before_ and _after_ the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.

View File

@@ -294,7 +294,7 @@ When using custom validation functions, Payload will use yours in place of the d
To reuse default field validations, call them from within your custom validation function:
```ts
import { text } from 'payload/shared'
import { text } from 'payload/fields/validations'
const field: Field = {
name: 'notBad',

View File

@@ -193,7 +193,7 @@ You can learn more about writing queries [here](/docs/queries/overview).
When a relationship field has both <strong>filterOptions</strong> and a custom{' '}
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
unless you call the default relationship field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
<strong>payload/fields/validations</strong> in your validate function.
</Banner>
## How the data is saved

View File

@@ -123,5 +123,5 @@ You can learn more about writing queries [here](/docs/queries/overview).
When an upload field has both <strong>filterOptions</strong> and a custom{' '}
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
unless you call the default upload field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
<strong>payload/fields/validations</strong> in your validate function.
</Banner>

View File

@@ -335,6 +335,7 @@ import {
FieldMap,
File,
Form,
FormFieldBase,
FormLoadingOverlayToggle,
FormSubmit,
GenerateConfirmation,

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"private": true,
"type": "module",
"scripts": {
@@ -119,7 +119,7 @@
"create-payload-app": "workspace:*",
"cross-env": "7.0.3",
"dotenv": "16.4.5",
"drizzle-orm": "0.32.1",
"drizzle-orm": "0.29.4",
"escape-html": "^1.0.3",
"execa": "5.1.1",
"form-data": "3.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",
@@ -50,7 +50,6 @@
"dependencies": {
"@clack/prompts": "^0.7.0",
"@sindresorhus/slugify": "^1.1.0",
"@swc/core": "^1.6.13",
"arg": "^5.0.0",
"chalk": "^4.1.0",
"comment-json": "^4.2.3",

View File

@@ -79,7 +79,7 @@ export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
const installSpinner = p.spinner()
installSpinner.start('Installing Payload and dependencies...')
const configurationResult = await installAndConfigurePayload({
const configurationResult = installAndConfigurePayload({
...args,
nextAppDetails,
nextConfigType,
@@ -143,16 +143,15 @@ async function addPayloadConfigToTsConfig(projectDir: string, isSrcDir: boolean)
}
}
async function installAndConfigurePayload(
function installAndConfigurePayload(
args: {
nextAppDetails: NextAppDetails
nextConfigType: NextConfigType
useDistFiles?: boolean
} & InitNextArgs,
): Promise<
):
| { payloadConfigPath: string; success: true }
| { payloadConfigPath?: string; reason: string; success: false }
> {
| { payloadConfigPath?: string; reason: string; success: false } {
const {
'--debug': debug,
nextAppDetails: { isSrcDir, nextAppDir, nextConfigPath } = {},
@@ -213,7 +212,7 @@ async function installAndConfigurePayload(
copyRecursiveSync(templateSrcDir, path.dirname(nextConfigPath), debug)
// Wrap next.config.js with withPayload
await wrapNextConfig({ nextConfigPath, nextConfigType })
wrapNextConfig({ nextConfigPath, nextConfigType })
return {
payloadConfigPath: path.resolve(nextAppDir, '../payload.config.ts'),
@@ -241,7 +240,7 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
const isSrcDir = fs.existsSync(path.resolve(projectDir, 'src'))
const nextConfigPath: string | undefined = (
await globby('next.config.*(t|j)s', { absolute: true, cwd: projectDir })
await globby('next.config.*js', { absolute: true, cwd: projectDir })
)?.[0]
if (!nextConfigPath || nextConfigPath.length === 0) {
@@ -287,13 +286,8 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
function getProjectType(args: {
nextConfigPath: string
packageObj: Record<string, unknown>
}): NextConfigType {
}): 'cjs' | 'esm' {
const { nextConfigPath, packageObj } = args
if (nextConfigPath.endsWith('.ts')) {
return 'ts'
}
if (nextConfigPath.endsWith('.mjs')) {
return 'esm'
}

View File

@@ -3,35 +3,6 @@ import { jest } from '@jest/globals'
import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js'
const tsConfigs = {
defaultNextConfig: `import type { NextConfig } from "next";
const nextConfig: NextConfig = {};
export default nextConfig;`,
nextConfigExportNamedDefault: `import type { NextConfig } from "next";
const nextConfig: NextConfig = {};
const wrapped = someFunc(asdf);
export { wrapped as default };
`,
nextConfigWithFunc: `import type { NextConfig } from "next";
const nextConfig: NextConfig = {};
export default someFunc(nextConfig);
`,
nextConfigWithFuncMultiline: `import type { NextConfig } from "next";
const nextConfig: NextConfig = {};
export default someFunc(
nextConfig
);
`,
nextConfigWithSpread: `import type { NextConfig } from "next";
const nextConfig: NextConfig = {
...someConfig,
};
export default nextConfig;
`,
}
const esmConfigs = {
defaultNextConfig: `/** @type {import('next').NextConfig} */
const nextConfig = {};
@@ -81,66 +52,27 @@ module.exports = nextConfig;
}
describe('parseAndInsertWithPayload', () => {
describe('ts', () => {
const configType = 'ts'
const importStatement = withPayloadStatement[configType]
it('should parse the default next config', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
tsConfigs.defaultNextConfig,
configType,
)
expect(modifiedConfigContent).toContain(importStatement)
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
})
it('should parse the config with a function', async () => {
const { modifiedConfigContent: modifiedConfigContent2 } = await parseAndModifyConfigContent(
tsConfigs.nextConfigWithFunc,
configType,
)
expect(modifiedConfigContent2).toContain('withPayload(someFunc(nextConfig))')
})
it('should parse the config with a multi-lined function', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
tsConfigs.nextConfigWithFuncMultiline,
configType,
)
expect(modifiedConfigContent).toContain(importStatement)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
})
it('should parse the config with a spread', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
tsConfigs.nextConfigWithSpread,
configType,
)
expect(modifiedConfigContent).toContain(importStatement)
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
})
})
describe('esm', () => {
const configType = 'esm'
const importStatement = withPayloadStatement[configType]
it('should parse the default next config', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the default next config', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
esmConfigs.defaultNextConfig,
configType,
)
expect(modifiedConfigContent).toContain(importStatement)
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
})
it('should parse the config with a function', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a function', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
esmConfigs.nextConfigWithFunc,
configType,
)
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))')
})
it('should parse the config with a multi-lined function', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a function on a new line', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
esmConfigs.nextConfigWithFuncMultiline,
configType,
)
@@ -148,8 +80,8 @@ describe('parseAndInsertWithPayload', () => {
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
})
it('should parse the config with a spread', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a spread', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
esmConfigs.nextConfigWithSpread,
configType,
)
@@ -158,10 +90,10 @@ describe('parseAndInsertWithPayload', () => {
})
// Unsupported: export { wrapped as default }
it('should give warning with a named export as default', async () => {
it('should give warning with a named export as default', () => {
const warnLogSpy = jest.spyOn(p.log, 'warn').mockImplementation(() => {})
const { modifiedConfigContent, success } = await parseAndModifyConfigContent(
const { modifiedConfigContent, success } = parseAndModifyConfigContent(
esmConfigs.nextConfigExportNamedDefault,
configType,
)
@@ -177,39 +109,39 @@ describe('parseAndInsertWithPayload', () => {
describe('cjs', () => {
const configType = 'cjs'
const requireStatement = withPayloadStatement[configType]
it('should parse the default next config', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the default next config', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.defaultNextConfig,
configType,
)
expect(modifiedConfigContent).toContain(requireStatement)
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
})
it('should parse anonymous default config', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse anonymous default config', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.anonConfig,
configType,
)
expect(modifiedConfigContent).toContain(requireStatement)
expect(modifiedConfigContent).toContain('withPayload({})')
})
it('should parse the config with a function', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a function', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.nextConfigWithFunc,
configType,
)
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))')
})
it('should parse the config with a multi-lined function', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a function on a new line', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.nextConfigWithFuncMultiline,
configType,
)
expect(modifiedConfigContent).toContain(requireStatement)
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
})
it('should parse the config with a named export as default', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a named export as default', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.nextConfigExportNamedDefault,
configType,
)
@@ -217,8 +149,8 @@ describe('parseAndInsertWithPayload', () => {
expect(modifiedConfigContent).toContain('withPayload(wrapped)')
})
it('should parse the config with a spread', async () => {
const { modifiedConfigContent } = await parseAndModifyConfigContent(
it('should parse the config with a spread', () => {
const { modifiedConfigContent } = parseAndModifyConfigContent(
cjsConfigs.nextConfigWithSpread,
configType,
)

View File

@@ -1,27 +1,25 @@
import type { ExportDefaultExpression, ModuleItem } from '@swc/core'
import type { Program } from 'esprima-next'
import swc from '@swc/core'
import chalk from 'chalk'
import { Syntax, parseModule } from 'esprima-next'
import fs from 'fs'
import type { NextConfigType } from '../types.js'
import { log, warning } from '../utils/log.js'
export const withPayloadStatement = {
cjs: `const { withPayload } = require("@payloadcms/next/withPayload");`,
esm: `import { withPayload } from "@payloadcms/next/withPayload";`,
ts: `import { withPayload } from "@payloadcms/next/withPayload";`,
cjs: `const { withPayload } = require('@payloadcms/next/withPayload')\n`,
esm: `import { withPayload } from '@payloadcms/next/withPayload'\n`,
}
export const wrapNextConfig = async (args: {
type NextConfigType = 'cjs' | 'esm'
export const wrapNextConfig = (args: {
nextConfigPath: string
nextConfigType: NextConfigType
}) => {
const { nextConfigPath, nextConfigType: configType } = args
const configContent = fs.readFileSync(nextConfigPath, 'utf8')
const { modifiedConfigContent: newConfig, success } = await parseAndModifyConfigContent(
const { modifiedConfigContent: newConfig, success } = parseAndModifyConfigContent(
configContent,
configType,
)
@@ -36,142 +34,113 @@ export const wrapNextConfig = async (args: {
/**
* Parses config content with AST and wraps it with withPayload function
*/
export async function parseAndModifyConfigContent(
export function parseAndModifyConfigContent(
content: string,
configType: NextConfigType,
): Promise<{ modifiedConfigContent: string; success: boolean }> {
content = withPayloadStatement[configType] + '\n' + content
): { modifiedConfigContent: string; success: boolean } {
content = withPayloadStatement[configType] + content
console.log({ configType, content })
if (configType === 'cjs' || configType === 'esm') {
try {
const ast = parseModule(content, { loc: true })
if (configType === 'cjs') {
// Find `module.exports = X`
const moduleExports = ast.body.find(
(p) =>
p.type === Syntax.ExpressionStatement &&
p.expression?.type === Syntax.AssignmentExpression &&
p.expression.left?.type === Syntax.MemberExpression &&
p.expression.left.object?.type === Syntax.Identifier &&
p.expression.left.object.name === 'module' &&
p.expression.left.property?.type === Syntax.Identifier &&
p.expression.left.property.name === 'exports',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any
if (moduleExports && moduleExports.expression.right?.loc) {
const modifiedConfigContent = insertBeforeAndAfter(
content,
moduleExports.expression.right.loc,
)
return { modifiedConfigContent, success: true }
}
return Promise.resolve({
modifiedConfigContent: content,
success: false,
})
} else if (configType === 'esm') {
const exportDefaultDeclaration = ast.body.find(
(p) => p.type === Syntax.ExportDefaultDeclaration,
) as Directive | undefined
const exportNamedDeclaration = ast.body.find(
(p) => p.type === Syntax.ExportNamedDeclaration,
) as ExportNamedDeclaration | undefined
if (!exportDefaultDeclaration && !exportNamedDeclaration) {
throw new Error('Could not find ExportDefaultDeclaration in next.config.js')
}
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) {
const modifiedConfigContent = insertBeforeAndAfter(
content,
exportDefaultDeclaration.declaration.loc,
)
return { modifiedConfigContent, success: true }
} else if (exportNamedDeclaration) {
const exportSpecifier = exportNamedDeclaration.specifiers.find(
(s) =>
s.type === 'ExportSpecifier' &&
s.exported?.name === 'default' &&
s.local?.type === 'Identifier' &&
s.local?.name,
)
if (exportSpecifier) {
warning('Could not automatically wrap next.config.js with withPayload.')
warning('Automatic wrapping of named exports as default not supported yet.')
warnUserWrapNotSuccessful(configType)
return {
modifiedConfigContent: content,
success: false,
}
}
}
warning('Could not automatically wrap Next config with withPayload.')
warnUserWrapNotSuccessful(configType)
return Promise.resolve({
modifiedConfigContent: content,
success: false,
})
}
} catch (error: unknown) {
if (error instanceof Error) {
warning(`Unable to parse Next config. Error: ${error.message} `)
warnUserWrapNotSuccessful(configType)
}
return {
modifiedConfigContent: content,
success: false,
}
let ast: Program | undefined
try {
ast = parseModule(content, { loc: true })
} catch (error: unknown) {
if (error instanceof Error) {
warning(`Unable to parse Next config. Error: ${error.message} `)
warnUserWrapNotSuccessful(configType)
}
} else if (configType === 'ts') {
const { moduleItems, parseOffset } = await compileTypeScriptFileToAST(content)
return {
modifiedConfigContent: content,
success: false,
}
}
const exportDefaultDeclaration = moduleItems.find(
(m) =>
m.type === 'ExportDefaultExpression' &&
(m.expression.type === 'Identifier' || m.expression.type === 'CallExpression'),
) as ExportDefaultExpression | undefined
if (configType === 'esm') {
const exportDefaultDeclaration = ast.body.find(
(p) => p.type === Syntax.ExportDefaultDeclaration,
) as Directive | undefined
if (exportDefaultDeclaration) {
if (!('span' in exportDefaultDeclaration.expression)) {
warning('Could not automatically wrap Next config with withPayload.')
warnUserWrapNotSuccessful(configType)
return Promise.resolve({
modifiedConfigContent: content,
success: false,
})
}
const exportNamedDeclaration = ast.body.find(
(p) => p.type === Syntax.ExportNamedDeclaration,
) as ExportNamedDeclaration | undefined
const modifiedConfigContent = insertBeforeAndAfterSWC(
if (!exportDefaultDeclaration && !exportNamedDeclaration) {
throw new Error('Could not find ExportDefaultDeclaration in next.config.js')
}
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) {
const modifiedConfigContent = insertBeforeAndAfter(
content,
exportDefaultDeclaration.expression.span,
parseOffset,
exportDefaultDeclaration.declaration.loc,
)
return { modifiedConfigContent, success: true }
} else if (exportNamedDeclaration) {
const exportSpecifier = exportNamedDeclaration.specifiers.find(
(s) =>
s.type === 'ExportSpecifier' &&
s.exported?.name === 'default' &&
s.local?.type === 'Identifier' &&
s.local?.name,
)
if (exportSpecifier) {
warning('Could not automatically wrap next.config.js with withPayload.')
warning('Automatic wrapping of named exports as default not supported yet.')
warnUserWrapNotSuccessful(configType)
return {
modifiedConfigContent: content,
success: false,
}
}
}
warning('Could not automatically wrap Next config with withPayload.')
warnUserWrapNotSuccessful(configType)
return {
modifiedConfigContent: content,
success: false,
}
} else if (configType === 'cjs') {
// Find `module.exports = X`
const moduleExports = ast.body.find(
(p) =>
p.type === Syntax.ExpressionStatement &&
p.expression?.type === Syntax.AssignmentExpression &&
p.expression.left?.type === Syntax.MemberExpression &&
p.expression.left.object?.type === Syntax.Identifier &&
p.expression.left.object.name === 'module' &&
p.expression.left.property?.type === Syntax.Identifier &&
p.expression.left.property.name === 'exports',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any
if (moduleExports && moduleExports.expression.right?.loc) {
const modifiedConfigContent = insertBeforeAndAfter(
content,
moduleExports.expression.right.loc,
)
return { modifiedConfigContent, success: true }
}
return {
modifiedConfigContent: content,
success: false,
}
}
warning('Could not automatically wrap Next config with withPayload.')
warnUserWrapNotSuccessful(configType)
return Promise.resolve({
return {
modifiedConfigContent: content,
success: false,
})
}
}
function warnUserWrapNotSuccessful(configType: NextConfigType) {
// Output directions for user to update next.config.js
const withPayloadMessage = `
${chalk.bold(`Please manually wrap your existing Next config with the withPayload function. Here is an example:`)}
${chalk.bold(`Please manually wrap your existing next.config.js with the withPayload function. Here is an example:`)}
${withPayloadStatement[configType]}
@@ -179,7 +148,7 @@ function warnUserWrapNotSuccessful(configType: NextConfigType) {
// Your Next.js config here
}
${configType === 'cjs' ? 'module.exports = withPayload(nextConfig)' : 'export default withPayload(nextConfig)'}
${configType === 'esm' ? 'export default withPayload(nextConfig)' : 'module.exports = withPayload(nextConfig)'}
`
@@ -217,7 +186,7 @@ type Loc = {
start: { column: number; line: number }
}
function insertBeforeAndAfter(content: string, loc: Loc): string {
function insertBeforeAndAfter(content: string, loc: Loc) {
const { end, start } = loc
const lines = content.split('\n')
@@ -236,57 +205,3 @@ function insertBeforeAndAfter(content: string, loc: Loc): string {
return lines.join('\n')
}
function insertBeforeAndAfterSWC(
content: string,
span: ModuleItem['span'],
/**
* WARNING: This is ONLY for unit tests. Defaults to 0 otherwise.
*
* @see compileTypeScriptFileToAST
*/
parseOffset: number,
): string {
const { end: preOffsetEnd, start: preOffsetStart } = span
const start = preOffsetStart - parseOffset
const end = preOffsetEnd - parseOffset
const insert = (pos: number, text: string): string => {
return content.slice(0, pos) + text + content.slice(pos)
}
// insert ) after end
content = insert(end - 1, ')')
// insert withPayload before start
content = insert(start - 1, 'withPayload(')
return content
}
/**
* Compile typescript to AST using the swc compiler
*/
async function compileTypeScriptFileToAST(
fileContent: string,
): Promise<{ moduleItems: ModuleItem[]; parseOffset: number }> {
let parseOffset = 0
/**
* WARNING: This is ONLY for unit tests.
*
* Multiple instances of swc DO NOT reset the .span.end value.
* During unit tests, the .spawn.end value is read and accounted for.
*
* https://github.com/swc-project/swc/issues/1366
*/
if (process.env.NODE_ENV === 'test') {
parseOffset = (await swc.parse('')).span.end
}
const module = await swc.parse(fileContent, {
syntax: 'typescript',
})
return { moduleItems: module.body, parseOffset }
}

View File

@@ -75,6 +75,6 @@ export type NextAppDetails = {
nextConfigType?: NextConfigType
}
export type NextConfigType = 'cjs' | 'esm' | 'ts'
export type NextConfigType = 'cjs' | 'esm'
export type StorageAdapterType = 'localDisk' | 'payloadCloud' | 'vercelBlobStorage'

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The officially supported MongoDB database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The officially supported Postgres database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {
@@ -47,8 +47,8 @@
"dependencies": {
"@payloadcms/drizzle": "workspace:*",
"console-table-printer": "2.11.2",
"drizzle-kit": "0.23.0-eb2ca29",
"drizzle-orm": "0.32.1",
"drizzle-kit": "0.20.14-1f2c838",
"drizzle-orm": "0.29.4",
"pg": "8.11.3",
"prompts": "2.4.2",
"to-snake-case": "1.0.0",

View File

@@ -65,7 +65,7 @@ export const createMigration: CreateMigration = async function createMigration(
const sqlStatementsUp = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)
const sqlStatementsDown = await generateMigration(drizzleJsonAfter, drizzleJsonBefore)
const sqlExecute = 'await payload.db.drizzle.execute(sql`'
const sqlExecute = 'await db.execute(sql`'
if (sqlStatementsUp?.length) {
upSQL = `${sqlExecute}\n ${sqlStatementsUp?.join('\n')}\`)`

View File

@@ -7,11 +7,10 @@ export const defaultDrizzleSnapshot: DrizzleSnapshotJSON = {
schemas: {},
tables: {},
},
dialect: 'postgresql',
dialect: 'pg',
enums: {},
prevId: '00000000-0000-0000-0000-00000000000',
schemas: {},
sequences: {},
tables: {},
version: '7',
version: '5',
}

View File

@@ -6,11 +6,11 @@ export const getMigrationTemplate = ({
upSQL,
}: MigrationTemplateArgs): string => `import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
${imports ? `${imports}\n` : ''}
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
${upSQL}
}
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
${downSQL}
}
`

View File

@@ -1,12 +1,14 @@
import type { Init, SanitizedCollectionConfig } from 'payload'
/* eslint-disable no-param-reassign */
import type { SanitizedCollectionConfig } from 'payload'
import type { Init } from 'payload'
import { createTableName } from '@payloadcms/drizzle'
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'
import toSnakeCase from 'to-snake-case'
import type { PostgresAdapter } from './types.js'
import { createTableName } from '../../drizzle/src/createTableName.js'
import { buildTable } from './schema/build.js'
export const init: Init = function init(this: PostgresAdapter) {

View File

@@ -156,7 +156,6 @@ declare module 'payload' {
export interface DatabaseAdapter
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
DrizzleAdapter {
drizzle: PostgresDB
enums: Record<string, GenericEnum>
/**
* An object keyed on each table, with a key value pair where the constraint name is the key, followed by the dot-notation field name

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-sqlite",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.36",
"description": "The officially supported SQLite database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {
@@ -46,8 +46,8 @@
"@libsql/client": "^0.6.2",
"@payloadcms/drizzle": "workspace:*",
"console-table-printer": "2.11.2",
"drizzle-kit": "0.23.0-eb2ca29",
"drizzle-orm": "0.32.1",
"drizzle-kit": "0.20.14-1f2c838",
"drizzle-orm": "0.29.4",
"prompts": "2.4.2",
"to-snake-case": "1.0.0",
"uuid": "9.0.0"

View File

@@ -66,7 +66,7 @@ export const createMigration: CreateMigration = async function createMigration(
const sqlStatementsUp = await generateSQLiteMigration(drizzleJsonBefore, drizzleJsonAfter)
const sqlStatementsDown = await generateSQLiteMigration(drizzleJsonAfter, drizzleJsonBefore)
// need to create tables as separate statements
const sqlExecute = 'await payload.db.drizzle.run(sql`'
const sqlExecute = 'await db.run(sql`'
if (sqlStatementsUp?.length) {
upSQL = sqlStatementsUp

View File

@@ -10,5 +10,5 @@ export const defaultDrizzleSnapshot: DrizzleSQLiteSnapshotJSON = {
enums: {},
prevId: '00000000-0000-0000-0000-00000000000',
tables: {},
version: '6',
version: '3',
}

View File

@@ -6,11 +6,11 @@ export const getMigrationTemplate = ({
upSQL,
}: MigrationTemplateArgs): string => `import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-sqlite'
${imports ? `${imports}\n` : ''}
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
${upSQL}
}
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
${downSQL}
}
`

View File

@@ -1,8 +1,9 @@
import type { Relation } from 'drizzle-orm'
/* eslint-disable no-param-reassign */
import type { ColumnDataType, Relation } from 'drizzle-orm'
import type {
AnySQLiteColumn,
ForeignKeyBuilder,
IndexBuilder,
SQLiteColumn,
SQLiteColumnBuilder,
SQLiteTableWithColumns,
UniqueConstraintBuilder,
@@ -31,7 +32,18 @@ import { traverseFields } from './traverseFields.js'
export type BaseExtraConfig = Record<
string,
(cols: {
[x: string]: AnySQLiteColumn
[x: string]: SQLiteColumn<{
baseColumn: never
columnType: string
data: unknown
dataType: ColumnDataType
driverParam: unknown
enumValues: string[]
hasDefault: false
name: string
notNull: false
tableName: string
}>
}) => ForeignKeyBuilder | IndexBuilder | UniqueConstraintBuilder
>

View File

@@ -1,7 +1,8 @@
import type { AnySQLiteColumn} from 'drizzle-orm/sqlite-core';
/* eslint-disable no-param-reassign */
import { index, uniqueIndex } from 'drizzle-orm/sqlite-core'
import type { GenericColumn } from '../types.js'
type CreateIndexArgs = {
columnName: string
name: string | string[]
@@ -10,7 +11,7 @@ type CreateIndexArgs = {
}
export const createIndex = ({ name, columnName, tableName, unique }: CreateIndexArgs) => {
return (table: { [x: string]: AnySQLiteColumn }) => {
return (table: { [x: string]: GenericColumn }) => {
let columns
if (Array.isArray(name)) {
columns = name

View File

@@ -1,10 +1,10 @@
import type { Client, Config, ResultSet } from '@libsql/client'
import type { Operators } from '@payloadcms/drizzle'
import type { BuildQueryJoinAliases, DrizzleAdapter } from '@payloadcms/drizzle/types'
import type { DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
import type { ColumnDataType, DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
import type {
AnySQLiteColumn,
SQLiteColumn,
SQLiteInsertOnConflictDoUpdateConfig,
SQLiteTableWithColumns,
SQLiteTransactionConfig,
@@ -25,8 +25,24 @@ export type Args = {
versionsSuffix?: string
}
export type GenericColumn = SQLiteColumn<
{
baseColumn: never
columnType: string
data: unknown
dataType: ColumnDataType
driverParam: unknown
enumValues: string[]
hasDefault: false
name: string
notNull: false
tableName: string
},
object
>
export type GenericColumns = {
[x: string]: AnySQLiteColumn
[x: string]: GenericColumn
}
export type GenericTable = SQLiteTableWithColumns<{
@@ -116,10 +132,12 @@ export type SQLiteAdapter = {
export type IDType = 'integer' | 'numeric' | 'text'
export type MigrateUpArgs = {
db: LibSQLDatabase
payload: Payload
req?: Partial<PayloadRequest>
}
export type MigrateDownArgs = {
db: LibSQLDatabase
payload: Payload
req?: Partial<PayloadRequest>
}
@@ -128,7 +146,6 @@ declare module 'payload' {
export interface DatabaseAdapter
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
DrizzleAdapter {
drizzle: LibSQLDatabase
/**
* An object keyed on each table, with a key value pair where the constraint name is the key, followed by the dot-notation field name
* Used for returning properly formed errors from unique fields

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/drizzle",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.36",
"description": "A library of shared functions used by different payload database adapters",
"homepage": "https://payloadcms.com",
"repository": {
@@ -39,7 +39,7 @@
},
"dependencies": {
"console-table-printer": "2.11.2",
"drizzle-orm": "0.32.1",
"drizzle-orm": "0.29.4",
"prompts": "2.4.2",
"to-snake-case": "1.0.0",
"uuid": "9.0.0"

View File

@@ -1,4 +1,5 @@
import type { Field, SanitizedConfig, TabAsField } from 'payload'
import type { Field, SanitizedConfig , TabAsField } from 'payload'
import { fieldAffectsData } from 'payload/shared'

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-nodemailer",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Payload Nodemailer Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/email-resend",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Payload Resend Email Adapter",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -39,7 +39,7 @@ export const index = deepMerge(
},
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/rules-of-hooks': 'warn',
},
},
)

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/graphql",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-react",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official React SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-vue",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official Vue SDK for Payload Live Preview",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official live preview JavaScript SDK for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -134,8 +134,12 @@ export const POST =
resHeaders.append(key, headers[key])
}
if (req.responseHeaders) {
mergeHeaders(req.responseHeaders, resHeaders)
}
return new Response(apiResponse.body, {
headers: req.responseHeaders ? mergeHeaders(req.responseHeaders, resHeaders) : resHeaders,
headers: resHeaders,
status: apiResponse.status,
})
}

View File

@@ -167,13 +167,7 @@ const handleCustomEndpoints = async ({
if (res instanceof Response) {
if (req.responseHeaders) {
const mergedResponse = new Response(res.body, {
headers: mergeHeaders(req.responseHeaders, res.headers),
status: res.status,
statusText: res.statusText,
})
return mergedResponse
mergeHeaders(req.responseHeaders, res.headers)
}
return res
@@ -385,13 +379,7 @@ export const GET =
if (res instanceof Response) {
if (req.responseHeaders) {
const mergedResponse = new Response(res.body, {
headers: mergeHeaders(req.responseHeaders, res.headers),
status: res.status,
statusText: res.statusText,
})
return mergedResponse
mergeHeaders(req.responseHeaders, res.headers)
}
return res
@@ -567,13 +555,7 @@ export const POST =
if (res instanceof Response) {
if (req.responseHeaders) {
const mergedResponse = new Response(res.body, {
headers: mergeHeaders(req.responseHeaders, res.headers),
status: res.status,
statusText: res.statusText,
})
return mergedResponse
mergeHeaders(req.responseHeaders, res.headers)
}
return res
@@ -661,13 +643,7 @@ export const DELETE =
if (res instanceof Response) {
if (req.responseHeaders) {
const mergedResponse = new Response(res.body, {
headers: mergeHeaders(req.responseHeaders, res.headers),
status: res.status,
statusText: res.statusText,
})
return mergedResponse
mergeHeaders(req.responseHeaders, res.headers)
}
return res
@@ -756,13 +732,7 @@ export const PATCH =
if (res instanceof Response) {
if (req.responseHeaders) {
const mergedResponse = new Response(res.body, {
headers: mergeHeaders(req.responseHeaders, res.headers),
status: res.status,
statusText: res.statusText,
})
return mergedResponse
mergeHeaders(req.responseHeaders, res.headers)
}
return res

View File

@@ -1,11 +1,33 @@
export const mergeHeaders = (sourceHeaders: Headers, destinationHeaders: Headers): Headers => {
// Create a new Headers object
const combinedHeaders = new Headers(destinationHeaders)
const headersToJoin = ['set-cookie', 'warning', 'www-authenticate', 'proxy-authenticate', 'vary']
// Append sourceHeaders to combinedHeaders
sourceHeaders.forEach((value, key) => {
combinedHeaders.append(key, value)
export function mergeHeaders(sourceHeaders: Headers, destinationHeaders: Headers): void {
// Create a map to store combined headers
const combinedHeaders = new Headers()
// Add existing destination headers to the combined map
destinationHeaders.forEach((value, key) => {
combinedHeaders.set(key, value)
})
return combinedHeaders
// Add source headers to the combined map, joining specific headers
sourceHeaders.forEach((value, key) => {
const lowerKey = key.toLowerCase()
if (headersToJoin.includes(lowerKey)) {
if (combinedHeaders.has(key)) {
combinedHeaders.set(key, `${combinedHeaders.get(key)}, ${value}`)
} else {
combinedHeaders.set(key, value)
}
} else {
combinedHeaders.set(key, value)
}
})
// Clear the destination headers and set the combined headers
destinationHeaders.forEach((_, key) => {
destinationHeaders.delete(key)
})
combinedHeaders.forEach((value, key) => {
destinationHeaders.append(key, value)
})
}

View File

@@ -1,11 +1,11 @@
'use client'
import type { FormProps } from '@payloadcms/ui'
import type { FieldMap } from '@payloadcms/ui/utilities/buildComponentMap'
import type {
ClientCollectionConfig,
ClientConfig,
ClientGlobalConfig,
Data,
FieldMap,
LivePreviewConfig,
} from 'payload'

View File

@@ -1,5 +1,6 @@
import type { StepNavItem } from '@payloadcms/ui'
import type { ClientCollectionConfig, ClientGlobalConfig, FieldMap } from 'payload'
import type { FieldMap } from '@payloadcms/ui/utilities/buildComponentMap'
import type { ClientCollectionConfig, ClientGlobalConfig } from 'payload'
import type React from 'react'
import { getTranslation } from '@payloadcms/translations'

View File

@@ -1,4 +1,4 @@
import type { MappedField } from 'payload'
import type { MappedField } from '@payloadcms/ui/utilities/buildComponentMap'
import { getTranslation } from '@payloadcms/translations'
import { getUniqueListBy } from 'payload/shared'

View File

@@ -1,8 +1,8 @@
'use client'
import type { ClientCollectionConfig, MappedField } from 'payload'
import type { ClientCollectionConfig } from 'payload'
import { getTranslation } from '@payloadcms/translations'
import { useConfig } from '@payloadcms/ui'
import { type MappedField, useConfig } from '@payloadcms/ui'
import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/shared'
import React from 'react'
import ReactDiffViewerImport from 'react-diff-viewer-continued'

View File

@@ -1,5 +1,7 @@
import type { I18nClient } from '@payloadcms/translations'
import type { MappedField, OptionObject, SelectField, SelectFieldProps } from 'payload'
import type { SelectFieldProps } from '@payloadcms/ui'
import type { MappedField } from '@payloadcms/ui/utilities/buildComponentMap'
import type { OptionObject, SelectField } from 'payload'
import { getTranslation } from '@payloadcms/translations'
import React from 'react'

View File

@@ -1,4 +1,4 @@
import type { MappedField, TabsFieldProps } from 'payload'
import type { MappedField, TabsFieldProps } from '@payloadcms/ui'
import React from 'react'

View File

@@ -1,5 +1,6 @@
import type { I18nClient } from '@payloadcms/translations'
import type { FieldMap, FieldPermissions, MappedField } from 'payload'
import type { FieldMap, MappedField } from '@payloadcms/ui/utilities/buildComponentMap'
import type { FieldPermissions } from 'payload'
import type React from 'react'
import type { DiffMethod } from 'react-diff-viewer-continued'

View File

@@ -1,5 +1,6 @@
import type { I18nClient } from '@payloadcms/translations'
import type { FieldMap, FieldPermissions, MappedField } from 'payload'
import type { FieldMap, MappedField } from '@payloadcms/ui/utilities/buildComponentMap'
import type { FieldPermissions } from 'payload'
import type { DiffMethod } from 'react-diff-viewer-continued'
import type { DiffComponents } from './fields/types.js'

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
"keywords": [
"admin panel",

View File

@@ -8,7 +8,6 @@ import type {
RelationshipField,
SelectField,
} from '../../fields/config/types.js'
import type { FormFieldBase } from '../types.js'
export type RowData = Record<string, any>
@@ -21,7 +20,7 @@ export type CellComponentProps = {
dateDisplayFormat?: DateField['admin']['date']['displayFormat']
fieldType?: Field['type']
isFieldAffectingData?: boolean
label?: FormFieldBase['label']
label?: Record<string, string> | string
labels?: Labels
link?: boolean
name: FieldBase['name']

View File

@@ -1,22 +0,0 @@
import type { ArrayField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type ArrayFieldProps = {
CustomRowLabel?: React.ReactNode
fieldMap: FieldMap
forceRender?: boolean
isSortable?: boolean
labels?: ArrayField['labels']
maxRows?: ArrayField['maxRows']
minRows?: ArrayField['minRows']
name?: string
width?: string
} & FormFieldBase
export type ArrayFieldLabelComponent = LabelComponent<'array'>
export type ArrayFieldDescriptionComponent = DescriptionComponent<'array'>
export type ArrayFieldErrorComponent = ErrorComponent<'array'>

View File

@@ -1,32 +0,0 @@
import type { Block, BlockField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type BlocksFieldProps = {
blocks?: ReducedBlock[]
forceRender?: boolean
isSortable?: boolean
labels?: BlockField['labels']
maxRows?: number
minRows?: number
name?: string
slug?: string
width?: string
} & FormFieldBase
export type ReducedBlock = {
LabelComponent: Block['admin']['components']['Label']
custom?: Record<any, string>
fieldMap: FieldMap
imageAltText?: string
imageURL?: string
labels: BlockField['labels']
slug: string
}
export type BlocksFieldLabelComponent = LabelComponent<'blocks'>
export type BlocksFieldDescriptionComponent = DescriptionComponent<'blocks'>
export type BlocksFieldErrorComponent = ErrorComponent<'blocks'>

View File

@@ -1,19 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type CheckboxFieldProps = {
checked?: boolean
disableFormData?: boolean
id?: string
name?: string
onChange?: (val: boolean) => void
partialChecked?: boolean
path?: string
width?: string
} & FormFieldBase
export type CheckboxFieldLabelComponent = LabelComponent<'checkbox'>
export type CheckboxFieldDescriptionComponent = DescriptionComponent<'checkbox'>
export type CheckboxFieldErrorComponent = ErrorComponent<'checkbox'>

View File

@@ -1,17 +0,0 @@
import type { CodeField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type CodeFieldProps = {
editorOptions?: CodeField['admin']['editorOptions']
language?: CodeField['admin']['language']
name?: string
path?: string
width: string
} & FormFieldBase
export type CodeFieldLabelComponent = LabelComponent<'code'>
export type CodeFieldDescriptionComponent = DescriptionComponent<'code'>
export type CodeFieldErrorComponent = ErrorComponent<'code'>

View File

@@ -1,15 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type CollapsibleFieldProps = {
fieldMap: FieldMap
initCollapsed?: boolean
width?: string
} & FormFieldBase
export type CollapsibleFieldLabelComponent = LabelComponent<'collapsible'>
export type CollapsibleFieldDescriptionComponent = DescriptionComponent<'collapsible'>
export type CollapsibleFieldErrorComponent = ErrorComponent<'collapsible'>

View File

@@ -1,17 +0,0 @@
import type { DateField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type DateFieldProps = {
date?: DateField['admin']['date']
name?: string
path?: string
placeholder?: DateField['admin']['placeholder'] | string
width?: string
} & FormFieldBase
export type DateFieldLabelComponent = LabelComponent<'date'>
export type DateFieldDescriptionComponent = DescriptionComponent<'date'>
export type DateFieldErrorComponent = ErrorComponent<'date'>

View File

@@ -1,17 +0,0 @@
import type { EmailField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type EmailFieldProps = {
autoComplete?: string
name?: string
path?: string
placeholder?: EmailField['admin']['placeholder']
width?: string
} & FormFieldBase
export type EmailFieldLabelComponent = LabelComponent<'email'>
export type EmailFieldDescriptionComponent = DescriptionComponent<'email'>
export type EmailFieldErrorComponent = ErrorComponent<'email'>

View File

@@ -1,17 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type GroupFieldProps = {
fieldMap: FieldMap
forceRender?: boolean
hideGutter?: boolean
name?: string
width?: string
} & FormFieldBase
export type GroupFieldLabelComponent = LabelComponent<'group'>
export type GroupFieldDescriptionComponent = DescriptionComponent<'group'>
export type GroupFieldErrorComponent = ErrorComponent<'group'>

View File

@@ -1,16 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type HiddenFieldProps = {
disableModifyingForm?: false
forceUsePathFromProps?: boolean
name?: string
path?: string
value?: unknown
} & FormFieldBase
export type HiddenFieldLabelComponent = LabelComponent<'hidden'>
export type HiddenFieldDescriptionComponent = DescriptionComponent<'hidden'>
export type HiddenFieldErrorComponent = ErrorComponent<'hidden'>

View File

@@ -1,17 +0,0 @@
import type { JSONField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type JSONFieldProps = {
editorOptions?: JSONField['admin']['editorOptions']
jsonSchema?: Record<string, unknown>
name?: string
path?: string
width?: string
} & FormFieldBase
export type JSONFieldLabelComponent = LabelComponent<'json'>
export type JSONFieldDescriptionComponent = DescriptionComponent<'json'>
export type JSONFieldErrorComponent = ErrorComponent<'json'>

View File

@@ -1,22 +0,0 @@
import type { NumberField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type NumberFieldProps = {
hasMany?: boolean
max?: number
maxRows?: number
min?: number
name?: string
onChange?: (e: number) => void
path?: string
placeholder?: NumberField['admin']['placeholder']
step?: number
width?: string
} & FormFieldBase
export type NumberFieldLabelComponent = LabelComponent<'number'>
export type NumberFieldDescriptionComponent = DescriptionComponent<'number'>
export type NumberFieldErrorComponent = ErrorComponent<'number'>

View File

@@ -1,16 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type PointFieldProps = {
name?: string
path?: string
placeholder?: string
step?: number
width?: string
} & FormFieldBase
export type PointFieldLabelComponent = LabelComponent<'point'>
export type PointFieldDescriptionComponent = DescriptionComponent<'point'>
export type PointFieldErrorComponent = ErrorComponent<'point'>

View File

@@ -1,21 +0,0 @@
import type { Option } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type RadioFieldProps = {
layout?: 'horizontal' | 'vertical'
name?: string
onChange?: OnChange
options?: Option[]
path?: string
value?: string
width?: string
} & FormFieldBase
export type OnChange<T = string> = (value: T) => void
export type RadioFieldLabelComponent = LabelComponent<'radio'>
export type RadioFieldDescriptionComponent = DescriptionComponent<'radio'>
export type RadioFieldErrorComponent = ErrorComponent<'radio'>

View File

@@ -1,19 +0,0 @@
import type { RelationshipField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type RelationshipFieldProps = {
allowCreate?: RelationshipField['admin']['allowCreate']
hasMany?: boolean
isSortable?: boolean
name: string
relationTo?: RelationshipField['relationTo']
sortOptions?: RelationshipField['admin']['sortOptions']
width?: string
} & FormFieldBase
export type RelationshipFieldLabelComponent = LabelComponent<'relationship'>
export type RelationshipFieldDescriptionComponent = DescriptionComponent<'relationship'>
export type RelationshipFieldErrorComponent = ErrorComponent<'relationship'>

View File

@@ -1,15 +0,0 @@
import type { ErrorComponent } from '../forms/Error.js'
import type { MappedField } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type RichTextComponentProps = {
name: string
richTextComponentMap?: Map<string, MappedField[] | React.ReactNode>
width?: string
} & FormFieldBase
export type RichTextFieldLabelComponent = LabelComponent<'richText'>
export type RichTextFieldDescriptionComponent = DescriptionComponent<'richText'>
export type RichTextFieldErrorComponent = ErrorComponent<'richText'>

View File

@@ -1,18 +0,0 @@
import type { DescriptionComponent, FormFieldBase, LabelComponent } from 'payload'
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
export type RowFieldProps = {
fieldMap: FieldMap
forceRender?: boolean
indexPath: string
path?: string
width?: string
} & FormFieldBase
export type RowFieldLabelComponent = LabelComponent<'row'>
export type RowFieldDescriptionComponent = DescriptionComponent<'row'>
export type RowFieldErrorComponent = ErrorComponent<'row'>

View File

@@ -1,21 +0,0 @@
import type { Option } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type SelectFieldProps = {
hasMany?: boolean
isClearable?: boolean
isSortable?: boolean
name?: string
onChange?: (e: string | string[]) => void
options?: Option[]
path?: string
value?: string
width?: string
} & FormFieldBase
export type SelectFieldLabelComponent = LabelComponent<'select'>
export type SelectFieldDescriptionComponent = DescriptionComponent<'select'>
export type SelectFieldErrorComponent = ErrorComponent<'select'>

View File

@@ -1,24 +0,0 @@
import type { TabsField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { FieldMap } from '../forms/FieldMap.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type TabsFieldProps = {
forceRender?: boolean
name?: string
path?: string
tabs?: MappedTab[]
width?: string
} & FormFieldBase
export type MappedTab = {
fieldMap?: FieldMap
label: TabsField['tabs'][0]['label']
name?: string
}
export type TabsFieldLabelComponent = LabelComponent<'tabs'>
export type TabsFieldDescriptionComponent = DescriptionComponent<'tabs'>
export type TabsFieldErrorComponent = ErrorComponent<'tabs'>

View File

@@ -1,23 +0,0 @@
import type { TextField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type TextFieldProps = {
hasMany?: boolean
inputRef?: React.MutableRefObject<HTMLInputElement>
maxLength?: number
maxRows?: number
minLength?: number
minRows?: number
name?: string
onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>
path?: string
placeholder?: TextField['admin']['placeholder']
width?: string
} & FormFieldBase
export type TextFieldLabelComponent = LabelComponent<'text'>
export type TextFieldDescriptionComponent = DescriptionComponent<'text'>
export type TextFieldErrorComponent = ErrorComponent<'text'>

View File

@@ -1,19 +0,0 @@
import type { TextareaField } from '../../fields/config/types.js'
import type { ErrorComponent } from '../forms/Error.js'
import type { DescriptionComponent, FormFieldBase, LabelComponent } from '../types.js'
export type TextareaFieldProps = {
maxLength?: number
minLength?: number
name?: string
path?: string
placeholder?: TextareaField['admin']['placeholder']
rows?: number
width?: string
} & FormFieldBase
export type TextareaFieldLabelComponent = LabelComponent<'textarea'>
export type TextareaFieldDescriptionComponent = DescriptionComponent<'textarea'>
export type TextareaFieldErrorComponent = ErrorComponent<'textarea'>

View File

@@ -1,17 +0,0 @@
import type { DescriptionComponent, FormFieldBase, LabelComponent, UploadField } from 'payload'
import type { ErrorComponent } from '../forms/Error.js'
export type UploadFieldProps = {
filterOptions?: UploadField['filterOptions']
name?: string
path?: string
relationTo?: UploadField['relationTo']
width?: string
} & FormFieldBase
export type UploadFieldLabelComponent = LabelComponent<'upload'>
export type UploadFieldDescriptionComponent = DescriptionComponent<'upload'>
export type UploadFieldErrorComponent = ErrorComponent<'upload'>

View File

@@ -1,86 +0,0 @@
import type { ArrayFieldProps } from './Array.js'
import type { BlocksFieldProps } from './Blocks.js'
import type { CheckboxFieldProps } from './Checkbox.js'
import type { CodeFieldProps } from './Code.js'
import type { CollapsibleFieldProps } from './Collapsible.js'
import type { DateFieldProps } from './Date.js'
import type { EmailFieldProps } from './Email.js'
import type { GroupFieldProps } from './Group.js'
import type { HiddenFieldProps } from './Hidden.js'
import type { JSONFieldProps } from './JSON.js'
import type { NumberFieldProps } from './Number.js'
import type { PointFieldProps } from './Point.js'
import type { RadioFieldProps } from './Radio.js'
import type { RelationshipFieldProps } from './Relationship.js'
import type { RichTextComponentProps } from './RichText.js'
import type { RowFieldProps } from './Row.js'
import type { SelectFieldProps } from './Select.js'
import type { TabsFieldProps } from './Tabs.js'
import type { TextFieldProps } from './Text.js'
import type { TextareaFieldProps } from './Textarea.js'
import type { UploadFieldProps } from './Upload.js'
export type FieldComponentProps =
| ({
type: 'array'
} & ArrayFieldProps)
| ({
type: 'blocks'
} & BlocksFieldProps)
| ({
type: 'checkbox'
} & CheckboxFieldProps)
| ({
type: 'code'
} & CodeFieldProps)
| ({
type: 'collapsible'
} & CollapsibleFieldProps)
| ({
type: 'date'
} & DateFieldProps)
| ({
type: 'email'
} & EmailFieldProps)
| ({
type: 'group'
} & GroupFieldProps)
| ({
type: 'hidden'
} & HiddenFieldProps)
| ({
type: 'json'
} & JSONFieldProps)
| ({
type: 'number'
} & NumberFieldProps)
| ({
type: 'point'
} & PointFieldProps)
| ({
type: 'radio'
} & RadioFieldProps)
| ({
type: 'relationship'
} & RelationshipFieldProps)
| ({
type: 'richText'
} & RichTextComponentProps)
| ({
type: 'row'
} & RowFieldProps)
| ({
type: 'select'
} & SelectFieldProps)
| ({
type: 'tabs'
} & TabsFieldProps)
| ({
type: 'text'
} & TextFieldProps)
| ({
type: 'textarea'
} & TextareaFieldProps)
| ({
type: 'upload'
} & UploadFieldProps)

View File

@@ -1,19 +1,7 @@
import type { CustomComponent, ServerProps } from '../../config/types.js'
import type { FieldComponentProps } from '../types.js'
import type { FieldTypes } from './FieldTypes.js'
export type GenericErrorProps = {
export type ErrorProps = {
CustomError?: React.ReactNode
alignCaret?: 'center' | 'left' | 'right'
message?: string
path?: string
showError?: boolean
}
export type ErrorProps<T extends keyof FieldTypes = any> = {
type: T
} & FieldComponentProps &
GenericErrorProps &
Partial<ServerProps>
export type ErrorComponent<T extends keyof FieldTypes = any> = CustomComponent<ErrorProps<T>>

View File

@@ -1,32 +0,0 @@
import type { User } from '../../auth/types.js'
import type { LabelStatic, Locale } from '../../config/types.js'
import type { 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 { SanitizedLabelProps } from './Label.js'
export type FormFieldBase = {
AfterInput?: React.ReactNode
BeforeInput?: React.ReactNode
CustomDescription?: React.ReactNode
CustomError?: React.ReactNode
CustomLabel?: React.ReactNode
className?: string
custom?: Record<string, any>
descriptionProps?: Omit<FieldDescriptionProps, 'type'>
disabled?: boolean
docPreferences?: DocumentPreferences
errorProps?: Omit<ErrorProps, 'type'>
label?: LabelStatic | false
labelProps?: SanitizedLabelProps
locale?: Locale
localized?: boolean
path?: string
readOnly?: boolean
required?: boolean
rtl?: boolean
style?: React.CSSProperties
user?: User
validate?: Validate
}

View File

@@ -1,24 +1,18 @@
import type React from 'react'
import type { CustomComponent, LabelFunction, ServerProps } from '../../config/types.js'
import type { FieldComponentProps } from '../types.js'
import type { FieldTypes } from './FieldTypes.js'
import type { CustomComponent, LabelFunction } from '../../config/types.js'
import type { Payload } from '../../index.js'
export type DescriptionFunction = LabelFunction
export type DescriptionComponent<T extends keyof FieldTypes = any> = CustomComponent<
FieldDescriptionProps<T>
>
export type DescriptionComponent = CustomComponent<FieldDescriptionProps>
export type Description = DescriptionFunction | Record<string, string> | string
export type GenericDescriptionProps = {
export type FieldDescriptionProps = {
CustomDescription?: React.ReactNode
className?: string
description?: Record<string, string> | string
marginPlacement?: 'bottom' | 'top'
payload?: Payload
}
export type FieldDescriptionProps<T extends keyof FieldTypes = any> = {
type: T
} & FieldComponentProps &
GenericDescriptionProps &
Partial<ServerProps>

View File

@@ -1,24 +0,0 @@
import type { CellComponentProps, FieldComponentProps } from '../types.js'
import type { FieldTypes } from './FieldTypes.js'
export type MappedField = {
CustomCell?: React.ReactNode
CustomField?: React.ReactNode
cellComponentProps: CellComponentProps
custom?: Record<any, string>
disableBulkEdit?: boolean
disableListColumn?: boolean
disableListFilter?: boolean
disabled?: boolean
fieldComponentProps: FieldComponentProps
fieldIsPresentational: boolean
isFieldAffectingData: boolean
isHidden?: boolean
isSidebar?: boolean
localized: boolean
name?: string
type: keyof FieldTypes
unique?: boolean
}
export type FieldMap = MappedField[]

View File

@@ -1,24 +1,11 @@
import type { CustomComponent, ServerProps } from '../../config/types.js'
import type { FieldComponentProps } from '../fields/index.js'
import type { FormFieldBase } from './Field.js'
import type { FieldTypes } from './FieldTypes.js'
export type GenericLabelProps = {
export type LabelProps = {
CustomLabel?: React.ReactNode
as?: 'label' | 'span'
htmlFor?: string
label?: Record<string, string> | string
required?: boolean
schemaPath?: string
unstyled?: boolean
} & FormFieldBase
}
export type LabelProps<T extends keyof FieldTypes = any> = {
type: T
} & FieldComponentProps &
GenericLabelProps &
Partial<ServerProps>
export type SanitizedLabelProps<T extends keyof FieldTypes = any> = Omit<
LabelProps<T>,
'label' | 'required'
>
export type LabelComponent<T extends keyof FieldTypes = any> = CustomComponent<LabelProps<T>>
export type SanitizedLabelProps = Omit<LabelProps, 'label' | 'required'>

View File

@@ -7,7 +7,6 @@ export type { CustomPreviewButton } from './elements/PreviewButton.js'
export type { CustomPublishButton } from './elements/PublishButton.js'
export type { CustomSaveButton } from './elements/SaveButton.js'
export type { CustomSaveDraftButton } from './elements/SaveDraftButton.js'
export type {
DocumentTab,
DocumentTabComponent,
@@ -15,191 +14,20 @@ export type {
DocumentTabConfig,
DocumentTabProps,
} from './elements/Tab.js'
export type { CustomUpload } from './elements/Upload.js'
export type {
WithServerSidePropsComponent,
WithServerSidePropsComponentProps,
} from './elements/WithServerSideProps.js'
export type {
ArrayFieldDescriptionComponent,
ArrayFieldErrorComponent,
ArrayFieldLabelComponent,
ArrayFieldProps,
} from './fields/Array.js'
export type { ReducedBlock } from './fields/Blocks.js'
export type {
BlocksFieldDescriptionComponent,
BlocksFieldErrorComponent,
BlocksFieldLabelComponent,
BlocksFieldProps,
} from './fields/Blocks.js'
export type {
CheckboxFieldDescriptionComponent,
CheckboxFieldErrorComponent,
CheckboxFieldLabelComponent,
CheckboxFieldProps,
} from './fields/Checkbox.js'
export type {
CodeFieldDescriptionComponent,
CodeFieldErrorComponent,
CodeFieldLabelComponent,
CodeFieldProps,
} from './fields/Code.js'
export type {
CollapsibleFieldDescriptionComponent,
CollapsibleFieldErrorComponent,
CollapsibleFieldLabelComponent,
CollapsibleFieldProps,
} from './fields/Collapsible.js'
export type {
DateFieldDescriptionComponent,
DateFieldErrorComponent,
DateFieldLabelComponent,
DateFieldProps,
} from './fields/Date.js'
export type {
EmailFieldDescriptionComponent,
EmailFieldErrorComponent,
EmailFieldLabelComponent,
EmailFieldProps,
} from './fields/Email.js'
export type {
GroupFieldDescriptionComponent,
GroupFieldErrorComponent,
GroupFieldLabelComponent,
GroupFieldProps,
} from './fields/Group.js'
export type {
HiddenFieldDescriptionComponent,
HiddenFieldErrorComponent,
HiddenFieldLabelComponent,
HiddenFieldProps,
} from './fields/Hidden.js'
export type {
JSONFieldDescriptionComponent,
JSONFieldErrorComponent,
JSONFieldLabelComponent,
JSONFieldProps,
} from './fields/JSON.js'
export type {
NumberFieldDescriptionComponent,
NumberFieldErrorComponent,
NumberFieldLabelComponent,
NumberFieldProps,
} from './fields/Number.js'
export type {
PointFieldDescriptionComponent,
PointFieldErrorComponent,
PointFieldLabelComponent,
PointFieldProps,
} from './fields/Point.js'
export type {
RadioFieldDescriptionComponent,
RadioFieldErrorComponent,
RadioFieldLabelComponent,
RadioFieldProps,
} from './fields/Radio.js'
export type {
RelationshipFieldDescriptionComponent,
RelationshipFieldErrorComponent,
RelationshipFieldLabelComponent,
RelationshipFieldProps,
} from './fields/Relationship.js'
export type {
RichTextComponentProps,
RichTextFieldDescriptionComponent,
RichTextFieldErrorComponent,
RichTextFieldLabelComponent,
} from './fields/RichText.js'
export type {
RowFieldDescriptionComponent,
RowFieldErrorComponent,
RowFieldLabelComponent,
RowFieldProps,
} from './fields/Row.js'
export type {
SelectFieldDescriptionComponent,
SelectFieldErrorComponent,
SelectFieldLabelComponent,
SelectFieldProps,
} from './fields/Select.js'
export type { MappedTab } from './fields/Tabs.js'
export type {
TabsFieldDescriptionComponent,
TabsFieldErrorComponent,
TabsFieldLabelComponent,
TabsFieldProps,
} from './fields/Tabs.js'
export type {
TextFieldDescriptionComponent,
TextFieldErrorComponent,
TextFieldLabelComponent,
TextFieldProps,
} from './fields/Text.js'
export type {
TextareaFieldDescriptionComponent,
TextareaFieldErrorComponent,
TextareaFieldLabelComponent,
TextareaFieldProps,
} from './fields/Textarea.js'
export type {
UploadFieldDescriptionComponent,
UploadFieldErrorComponent,
UploadFieldLabelComponent,
UploadFieldProps,
} from './fields/Upload.js'
export type { FieldComponentProps } from './fields/index.js'
export type { ErrorComponent, ErrorProps, GenericErrorProps } from './forms/Error.js'
export type { FormFieldBase } from './forms/Field.js'
export type { ErrorProps } from './forms/Error.js'
export type {
Description,
DescriptionComponent,
DescriptionFunction,
FieldDescriptionProps,
GenericDescriptionProps,
} from './forms/FieldDescription.js'
export type { MappedField } from './forms/FieldMap.js'
export type { FieldMap } from './forms/FieldMap.js'
export type { Data, FilterOptionsResult, FormField, FormState, Row } from './forms/Form.js'
export type {
GenericLabelProps,
LabelComponent,
LabelProps,
SanitizedLabelProps,
} from './forms/Label.js'
export type { LabelProps, SanitizedLabelProps } from './forms/Label.js'
export type { RowLabel, RowLabelComponent } from './forms/RowLabel.js'

View File

@@ -23,7 +23,6 @@ import type {
EntityDescriptionComponent,
GeneratePreviewURL,
LabelFunction,
LabelStatic,
LivePreviewConfig,
OpenGraphConfig,
} from '../../config/types.js'
@@ -439,8 +438,8 @@ export type CollectionConfig<TSlug extends CollectionSlug = any> = {
* Label configuration
*/
labels?: {
plural?: LabelFunction | LabelStatic
singular?: LabelFunction | LabelStatic
plural?: LabelFunction | Record<string, string> | string
singular?: LabelFunction | Record<string, string> | string
}
slug: string
/**

View File

@@ -423,8 +423,6 @@ export type LocalizationConfig = Prettify<
export type LabelFunction = ({ t }: { t: TFunction }) => string
export type LabelStatic = Record<string, string> | string
export type SharpDependency = (
input?:
| ArrayBuffer

View File

@@ -9,19 +9,19 @@ import type { JSONSchema4 } from 'json-schema'
import type React from 'react'
import type { RichTextAdapter, RichTextAdapterProvider } from '../../admin/RichText.js'
import type { ErrorComponent } from '../../admin/forms/Error.js'
import type {
ConditionalDateProps,
Description,
DescriptionComponent,
LabelComponent,
ErrorProps,
LabelProps,
RowLabelComponent,
} from '../../admin/types.js'
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'
import type { CustomComponent, LabelFunction, LabelStatic } from '../../config/types.js'
import type { CustomComponent, LabelFunction } from '../../config/types.js'
import type { DBIdentifierName } from '../../database/types.js'
import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
import type { CollectionSlug } from '../../index.js'
import type { CollectionSlug, GeneratedTypes } from '../../index.js'
import type { DocumentPreferences } from '../../preferences/types.js'
import type { Operation, PayloadRequest, RequestContext, Where } from '../../types/index.js'
import type { ClientFieldConfig } from './client.js'
@@ -123,10 +123,6 @@ export type FilterOptionsProps<TData = any> = {
user: Partial<PayloadRequest['user']>
}
export type FilterOptionsFunc<TData = any> = (
options: FilterOptionsProps<TData>,
) => Promise<Where | boolean> | Where | boolean
export type FilterOptions<TData = any> =
| ((options: FilterOptionsProps<TData>) => Promise<Where | boolean> | Where | boolean)
| Where
@@ -171,8 +167,8 @@ type Admin = {
}
export type Labels = {
plural: LabelFunction | LabelStatic
singular: LabelFunction | LabelStatic
plural: LabelFunction | Record<string, string> | string
singular: LabelFunction | Record<string, string> | string
}
export type BaseValidateOptions<TData, TSiblingData> = {
@@ -203,7 +199,7 @@ export type Validate<
export type ClientValidate = Omit<Validate, 'req'>
export type OptionObject = {
label: LabelFunction | LabelStatic
label: LabelFunction | Record<string, string> | string
value: string
}
@@ -231,7 +227,7 @@ export interface FieldBase {
beforeValidate?: FieldHook[]
}
index?: boolean
label?: LabelFunction | LabelStatic | false
label?: LabelFunction | Record<string, string> | false | string
localized?: boolean
/**
* The name of the field. Must be alphanumeric and cannot contain ' . '
@@ -256,8 +252,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<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -295,8 +291,8 @@ export type TextField = {
admin?: {
autoComplete?: string
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -330,8 +326,8 @@ export type EmailField = {
admin?: {
autoComplete?: string
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -343,8 +339,8 @@ export type EmailField = {
export type TextareaField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -360,8 +356,8 @@ export type TextareaField = {
export type CheckboxField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -372,8 +368,8 @@ export type CheckboxField = {
export type DateField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
afterInput?: CustomComponent[]
beforeInput?: CustomComponent[]
}
@@ -508,8 +504,8 @@ export type UIField = {
export type UploadField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
}
filterOptions?: FilterOptions
@@ -525,8 +521,8 @@ export type UploadField = {
type CodeAdmin = {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
editorOptions?: EditorProps['options']
language?: string
@@ -541,8 +537,8 @@ export type CodeField = {
type JSONAdmin = {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
editorOptions?: EditorProps['options']
} & Admin
@@ -560,8 +556,8 @@ export type JSONField = {
export type SelectField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
isClearable?: boolean
isSortable?: boolean
@@ -622,8 +618,8 @@ type SharedRelationshipProperties = {
type RelationshipAdmin = {
allowCreate?: boolean
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
isSortable?: boolean
} & Admin
@@ -663,8 +659,8 @@ export type RichTextField<
> = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
} & Admin
editor?:
@@ -712,8 +708,8 @@ export type ArrayField = {
export type RadioField = {
admin?: {
components?: {
Error?: ErrorComponent
Label?: LabelComponent
Error?: CustomComponent<ErrorProps>
Label?: CustomComponent<LabelProps>
}
layout?: 'horizontal' | 'vertical'
} & Admin

View File

@@ -6,6 +6,7 @@ import type { Field, FieldHookArgs, TabAsField, ValidateOptions } from '../../co
import { MissingEditorProp } from '../../../errors/index.js'
import { deepMergeWithSourceArrays } from '../../../utilities/deepMerge.js'
import { formatErrorLabels } from '../../../utilities/formatLabels.js'
import { fieldAffectsData, tabHasName } from '../../config/types.js'
import { getFieldPaths } from '../../getFieldPaths.js'
import { beforeDuplicate } from './beforeDuplicate.js'
@@ -146,7 +147,7 @@ export const promise = async ({
if (typeof validationResult === 'string') {
errors.push({
field: fieldPath.join('.'),
field: formatErrorLabels(fieldPath),
message: validationResult,
})
}

View File

@@ -981,7 +981,7 @@ export {
deepMergeWithSourceArrays,
} from './utilities/deepMerge.js'
export { default as flattenTopLevelFields } from './utilities/flattenTopLevelFields.js'
export { formatLabels, formatNames, toWords } from './utilities/formatLabels.js'
export { formatErrorLabels, formatLabels, formatNames, toWords } from './utilities/formatLabels.js'
export { getCollectionIDFieldTypes } from './utilities/getCollectionIDFieldTypes.js'
export { getObjectDotNotation } from './utilities/getObjectDotNotation.js'
export { initTransaction } from './utilities/initTransaction.js'

View File

@@ -1,4 +1,4 @@
import { formatLabels, toWords } from './formatLabels'
import { formatErrorLabels, formatLabels, toWords } from './formatLabels'
describe('formatLabels', () => {
it('should format singular slug', () => {
@@ -39,3 +39,11 @@ describe('formatLabels', () => {
})
})
})
describe('formatErrorLabels', () => {
it('should format array', () => {
expect(formatErrorLabels(['test', 1, 'field', 'array', 3, 'final'])).toBe(
'Test (1) > Field > Array (3) > Final',
)
})
})

View File

@@ -9,7 +9,8 @@ const toWords = (inputString: string, joinWords = false): string => {
const trimmedString = notNullString.trim()
const arrayOfStrings = trimmedString.split(/[\s-]/)
const splitStringsArray = []
const splitStringsArray: string[] = []
arrayOfStrings.forEach((tempString) => {
if (tempString !== '') {
const splitWords = tempString.split(/(?=[A-Z])/).join(' ')
@@ -46,4 +47,23 @@ const formatNames = (slug: string): { plural: string; singular: string } => {
}
}
export { formatLabels, formatNames, toWords }
/**
* Formats labels for error field schema array.
* @param fieldSchema - Array of strings and numbers.
* @returns Formatted string.
*
* @example
* formatErrorLabels(['test', 1, 'test2']) // => 'Test (1) > Test2'
*/
const formatErrorLabels = (fieldSchema: (number | string)[]): string => {
return fieldSchema.reduce((acc: string, current, index) => {
if (typeof current === 'number') {
return index === 0 ? `(${current})` : `${acc} (${current})`
} else {
const formattedLabel = current.charAt(0).toUpperCase() + current.slice(1)
return index === 0 ? `${acc}${formattedLabel}` : `${acc} > ${formattedLabel}`
}
}, '') as string
}
export { formatErrorLabels, formatLabels, formatNames, toWords }

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official cloud storage plugin for Payload CMS",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-cloud",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official Payload Cloud plugin",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-form-builder",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Form builder plugin for Payload CMS",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
'use client'
import type { TextFieldProps } from 'payload'
import type { TextFieldProps } from '@payloadcms/ui'
import { SelectField, useForm } from '@payloadcms/ui'
import React, { useEffect, useState } from 'react'
@@ -34,5 +34,7 @@ export const DynamicFieldSelector: React.FC<TextFieldProps> = (props) => {
}
}, [fields, getDataByPath])
// TODO: label from config is Record<string, string> | false | string
// but the FormFieldBase type has only label?: string, changing FormFieldBase breaks other ui components
return <SelectField {...props} options={options} />
}

View File

@@ -1,6 +1,7 @@
'use client'
import type { Data, TextFieldProps } from 'payload'
import type { TextFieldProps } from '@payloadcms/ui'
import type { Data } from 'payload'
import { TextField, useLocale, useWatchForm } from '@payloadcms/ui'
import React, { useEffect, useState } from 'react'

View File

@@ -2,7 +2,7 @@ import type { Block, CollectionConfig, Field } from 'payload'
import { deepMergeWithSourceArrays } from 'payload'
import type { FormBuilderPluginConfig } from '../../types.js'
import type { FieldConfig, FormBuilderPluginConfig } from '../../types.js'
import { fields } from './fields.js'
@@ -157,9 +157,7 @@ export const generateFormCollection = (formConfig: FormBuilderPluginConfig): Col
name: 'cc',
type: 'text',
admin: {
style: {
maxWidth: '50%',
},
width: '50%',
},
label: 'CC',
},
@@ -167,9 +165,7 @@ export const generateFormCollection = (formConfig: FormBuilderPluginConfig): Col
name: 'bcc',
type: 'text',
admin: {
style: {
maxWidth: '50%',
},
width: '50%',
},
label: 'BCC',
},

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "The official Nested Docs plugin for Payload",
"homepage": "https://payloadcms.com",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Redirects plugin for Payload",
"keywords": [
"payload",

View File

@@ -8,8 +8,6 @@ Minimum required version of Payload: `1.9.5`
It injects a `beforeChange` field hook into each `relationship` and `upload` field, which converts string-based IDs to `ObjectID`s immediately prior to storage.
By default, it also injects an `afterRead` field hook into the above fields, which ensures that the values are re-formatted back to strings after having been read from the database.
#### Usage
Simply import and install the plugin to make it work:
@@ -22,11 +20,7 @@ export default buildConfig({
// your config here
plugins: [
// Call the plugin within your `plugins` array
relationshipsAsObjectID({
// Optionally keep relationship values as ObjectID
// when they are retrieved from the database.
keepAfterRead: true,
}),
relationshipsAsObjectID(),
],
})
```

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-relationship-object-ids",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "A Payload plugin to store all relationship IDs as ObjectIDs",
"repository": {
"type": "git",

View File

@@ -1,101 +0,0 @@
import type { CollectionConfig, Config, FieldHook, RelationshipField, UploadField } from 'payload'
import mongoose from 'mongoose'
import { fieldAffectsData } from 'payload/shared'
const convertValue = ({
relatedCollection,
value,
}: {
relatedCollection: CollectionConfig
value: number | string
}): mongoose.Types.ObjectId | number | string => {
const customIDField = relatedCollection.fields.find(
(field) => fieldAffectsData(field) && field.name === 'id',
)
if (!customIDField && mongoose.Types.ObjectId.isValid(value)) {
return value.toString()
}
return value
}
interface RelationObject {
relationTo: string
value: number | string
}
function isValidRelationObject(value: unknown): value is RelationObject {
return typeof value === 'object' && value !== null && 'relationTo' in value && 'value' in value
}
interface Args {
config: Config
field: RelationshipField | UploadField
}
export const getAfterReadHook =
({ config, field }: Args): FieldHook =>
({ value }) => {
let relatedCollection: CollectionConfig | undefined
const hasManyRelations = typeof field.relationTo !== 'string'
if (!hasManyRelations) {
relatedCollection = config.collections?.find(({ slug }) => slug === field.relationTo)
}
if (Array.isArray(value)) {
return value.map((val) => {
// Handle has many
if (relatedCollection && val) {
return convertValue({
relatedCollection,
value: val,
})
}
// Handle has many - polymorphic
if (isValidRelationObject(val)) {
const relatedCollectionForSingleValue = config.collections?.find(
({ slug }) => slug === val.relationTo,
)
if (relatedCollectionForSingleValue) {
return {
relationTo: val.relationTo,
value: convertValue({
relatedCollection: relatedCollectionForSingleValue,
value: val.value,
}),
}
}
}
return val
})
}
// Handle has one - polymorphic
if (isValidRelationObject(value)) {
relatedCollection = config.collections?.find(({ slug }) => slug === value.relationTo)
if (relatedCollection) {
return {
relationTo: value.relationTo,
value: convertValue({ relatedCollection, value: value.value }),
}
}
}
// Handle has one
if (relatedCollection && value) {
return convertValue({
relatedCollection,
value,
})
}
return value
}

View File

@@ -1,28 +1,14 @@
import type { Config, Field, FieldHook } from 'payload'
import type { Config, Field } from 'payload'
import { getAfterReadHook } from './hooks/afterRead.js'
import { getBeforeChangeHook } from './hooks/beforeChange.js'
interface TraverseFieldsArgs {
config: Config
fields: Field[]
keepAfterRead: boolean
}
const traverseFields = ({ config, fields, keepAfterRead }: TraverseFieldsArgs): Field[] => {
const traverseFields = ({ config, fields }: { config: Config; fields: Field[] }): Field[] => {
return fields.map((field) => {
if (field.type === 'relationship' || field.type === 'upload') {
const afterRead: FieldHook[] = [...(field.hooks?.afterRead || [])]
if (!keepAfterRead) {
afterRead.unshift(getAfterReadHook({ config, field }))
}
return {
...field,
hooks: {
...(field.hooks || {}),
afterRead,
beforeChange: [
...(field.hooks?.beforeChange || []),
getBeforeChangeHook({ config, field }),
@@ -34,7 +20,7 @@ const traverseFields = ({ config, fields, keepAfterRead }: TraverseFieldsArgs):
if ('fields' in field) {
return {
...field,
fields: traverseFields({ config, fields: field.fields, keepAfterRead }),
fields: traverseFields({ config, fields: field.fields }),
}
}
@@ -44,7 +30,7 @@ const traverseFields = ({ config, fields, keepAfterRead }: TraverseFieldsArgs):
tabs: field.tabs.map((tab) => {
return {
...tab,
fields: traverseFields({ config, fields: tab.fields, keepAfterRead }),
fields: traverseFields({ config, fields: tab.fields }),
}
}),
}
@@ -56,7 +42,7 @@ const traverseFields = ({ config, fields, keepAfterRead }: TraverseFieldsArgs):
blocks: field.blocks.map((block) => {
return {
...block,
fields: traverseFields({ config, fields: block.fields, keepAfterRead }),
fields: traverseFields({ config, fields: block.fields }),
}
}),
}
@@ -66,19 +52,9 @@ const traverseFields = ({ config, fields, keepAfterRead }: TraverseFieldsArgs):
})
}
interface Args {
/*
If you want to keep ObjectIDs as ObjectIDs after read, you can enable this flag.
By default, all relationship ObjectIDs are stringified within the AfterRead hook.
*/
keepAfterRead?: boolean
}
export const relationshipsAsObjectID =
(args?: Args) =>
(/** Possible args in the future */) =>
(config: Config): Config => {
const keepAfterRead = typeof args?.keepAfterRead === 'boolean' ? args.keepAfterRead : false
return {
...config,
collections: (config.collections || []).map((collection) => {
@@ -87,7 +63,6 @@ export const relationshipsAsObjectID =
fields: traverseFields({
config,
fields: collection.fields,
keepAfterRead,
}),
}
}),
@@ -97,7 +72,6 @@ export const relationshipsAsObjectID =
fields: traverseFields({
config,
fields: global.fields,
keepAfterRead,
}),
}
}),

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "Search plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-beta.71",
"version": "3.0.0-beta.68",
"description": "SEO plugin for Payload",
"keywords": [
"payload",

View File

@@ -1,7 +1,6 @@
'use client'
import type { FieldType, Options } from '@payloadcms/ui'
import type { FormFieldBase } from 'payload'
import type { FieldType, FormFieldBase, Options } from '@payloadcms/ui'
import {
FieldLabel,
@@ -83,9 +82,7 @@ export const MetaDescriptionComponent: React.FC<MetaDescriptionProps> = (props)
<React.Fragment>
&nbsp; &mdash; &nbsp;
<button
onClick={() => {
void regenerateDescription()
}}
onClick={regenerateDescription}
style={{
background: 'none',
backgroundColor: 'transparent',

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