feat(richtext-lexical)!: initialize lexical during sanitization (#6119)
BREAKING: - sanitizeFields is now an async function - the richText adapters now return a function instead of returning the adapter directly
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import type { User } from 'payload/auth'
|
||||
import type { Config } from 'payload/config'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
export const getBaseFields = (config: Config): Field[] => [
|
||||
export const getBaseFields = (config: SanitizedConfig): Field[] => [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
import type { Config, SanitizedConfig } from 'payload/config'
|
||||
import type { Field } from 'payload/types'
|
||||
import type { Editor } from 'slate'
|
||||
|
||||
@@ -35,16 +35,15 @@ export const wrapLink = (editor: Editor): void => {
|
||||
*/
|
||||
export function transformExtraFields(
|
||||
customFieldSchema:
|
||||
| ((args: { config: SanitizedConfig; defaultFields: Field[]; i18n: I18n }) => Field[])
|
||||
| ((args: { config: SanitizedConfig; defaultFields: Field[] }) => Field[])
|
||||
| Field[],
|
||||
config: SanitizedConfig,
|
||||
i18n: I18n,
|
||||
): Field[] {
|
||||
const baseFields: Field[] = getBaseFields(config)
|
||||
|
||||
const fields =
|
||||
typeof customFieldSchema === 'function'
|
||||
? customFieldSchema({ config, defaultFields: baseFields, i18n })
|
||||
? customFieldSchema({ config, defaultFields: baseFields })
|
||||
: baseFields
|
||||
|
||||
// Wrap fields which are not part of the base schema in a group named 'fields' - otherwise they will be rendered but not saved
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import type { RichTextAdapter } from 'payload/types'
|
||||
import type { Field, RichTextAdapter } from 'payload/types'
|
||||
|
||||
import { mapFields } from '@payloadcms/ui/utilities/buildComponentMap'
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
import React from 'react'
|
||||
|
||||
import type { AdapterArguments, RichTextCustomElement, RichTextCustomLeaf } from './types.js'
|
||||
|
||||
import { elements as elementTypes } from './field/elements/index.js'
|
||||
import { linkFieldsSchemaPath } from './field/elements/link/shared.js'
|
||||
import { transformExtraFields } from './field/elements/link/utilities.js'
|
||||
import { uploadFieldsSchemaPath } from './field/elements/upload/shared.js'
|
||||
import { defaultLeaves as leafTypes } from './field/leaves/index.js'
|
||||
|
||||
@@ -17,8 +15,6 @@ export const getGenerateComponentMap =
|
||||
({ WithServerSideProps, config, i18n }) => {
|
||||
const componentMap = new Map()
|
||||
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
;(args?.admin?.leaves || Object.values(leafTypes)).forEach((leaf) => {
|
||||
let leafObject: RichTextCustomLeaf
|
||||
|
||||
@@ -66,16 +62,10 @@ export const getGenerateComponentMap =
|
||||
|
||||
switch (element.name) {
|
||||
case 'link': {
|
||||
const linkFields = sanitizeFields({
|
||||
config,
|
||||
fields: transformExtraFields(args.admin?.link?.fields, config, i18n),
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
const mappedFields = mapFields({
|
||||
WithServerSideProps,
|
||||
config,
|
||||
fieldSchema: linkFields,
|
||||
fieldSchema: args.admin?.link?.fields as Field[],
|
||||
i18n,
|
||||
readOnly: false,
|
||||
})
|
||||
@@ -98,16 +88,10 @@ export const getGenerateComponentMap =
|
||||
|
||||
uploadEnabledCollections.forEach((collection) => {
|
||||
if (args?.admin?.upload?.collections[collection.slug]?.fields) {
|
||||
const uploadFields = sanitizeFields({
|
||||
config,
|
||||
fields: args?.admin?.upload?.collections[collection.slug]?.fields,
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
const mappedFields = mapFields({
|
||||
WithServerSideProps,
|
||||
config,
|
||||
fieldSchema: uploadFields,
|
||||
fieldSchema: args?.admin?.upload?.collections[collection.slug]?.fields,
|
||||
i18n,
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import type { RichTextAdapter } from 'payload/types'
|
||||
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
import type { Field, RichTextAdapter } from 'payload/types'
|
||||
|
||||
import type { AdapterArguments, RichTextCustomElement } from './types.js'
|
||||
|
||||
import { elements as elementTypes } from './field/elements/index.js'
|
||||
import { linkFieldsSchemaPath } from './field/elements/link/shared.js'
|
||||
import { transformExtraFields } from './field/elements/link/utilities.js'
|
||||
import { uploadFieldsSchemaPath } from './field/elements/upload/shared.js'
|
||||
|
||||
export const getGenerateSchemaMap =
|
||||
(args: AdapterArguments): RichTextAdapter['generateSchemaMap'] =>
|
||||
({ config, i18n, schemaMap, schemaPath }) => {
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
({ config, schemaMap, schemaPath }) => {
|
||||
;(args?.admin?.elements || Object.values(elementTypes)).forEach((el) => {
|
||||
let element: RichTextCustomElement
|
||||
|
||||
@@ -26,13 +21,10 @@ export const getGenerateSchemaMap =
|
||||
if (element) {
|
||||
switch (element.name) {
|
||||
case 'link': {
|
||||
const linkFields = sanitizeFields({
|
||||
config,
|
||||
fields: transformExtraFields(args.admin?.link?.fields, config, i18n),
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
schemaMap.set(`${schemaPath}.${linkFieldsSchemaPath}`, linkFields)
|
||||
schemaMap.set(
|
||||
`${schemaPath}.${linkFieldsSchemaPath}`,
|
||||
args.admin?.link?.fields as Field[],
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
@@ -50,15 +42,9 @@ export const getGenerateSchemaMap =
|
||||
|
||||
uploadEnabledCollections.forEach((collection) => {
|
||||
if (args?.admin?.upload?.collections[collection.slug]?.fields) {
|
||||
const uploadFields = sanitizeFields({
|
||||
config,
|
||||
fields: args?.admin?.upload?.collections[collection.slug]?.fields,
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
schemaMap.set(
|
||||
`${schemaPath}.${uploadFieldsSchemaPath}.${collection.slug}`,
|
||||
uploadFields,
|
||||
args?.admin?.upload?.collections[collection.slug]?.fields,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { RichTextAdapter } from 'payload/types'
|
||||
import type { Config } from 'payload/config'
|
||||
import type { RichTextAdapterProvider } from 'payload/types'
|
||||
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
import { withNullableJSONSchemaType } from 'payload/utilities'
|
||||
|
||||
import type { AdapterArguments } from './types.js'
|
||||
@@ -7,61 +9,95 @@ import type { AdapterArguments } from './types.js'
|
||||
import { RichTextCell } from './cell/index.js'
|
||||
import { richTextRelationshipPromise } from './data/richTextRelationshipPromise.js'
|
||||
import { richTextValidate } from './data/validation.js'
|
||||
import { transformExtraFields } from './field/elements/link/utilities.js'
|
||||
import { RichTextField } from './field/index.js'
|
||||
import { getGenerateComponentMap } from './generateComponentMap.js'
|
||||
import { getGenerateSchemaMap } from './generateSchemaMap.js'
|
||||
|
||||
export function slateEditor(args: AdapterArguments): RichTextAdapter<any[], AdapterArguments, any> {
|
||||
return {
|
||||
CellComponent: RichTextCell,
|
||||
FieldComponent: RichTextField,
|
||||
generateComponentMap: getGenerateComponentMap(args),
|
||||
generateSchemaMap: getGenerateSchemaMap(args),
|
||||
outputSchema: ({ isRequired }) => {
|
||||
return {
|
||||
type: withNullableJSONSchemaType('array', isRequired),
|
||||
items: {
|
||||
type: 'object',
|
||||
},
|
||||
export function slateEditor(
|
||||
args: AdapterArguments,
|
||||
): RichTextAdapterProvider<any[], AdapterArguments, any> {
|
||||
return async ({ config }) => {
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
if (!args.admin) {
|
||||
args.admin = {}
|
||||
}
|
||||
if (!args.admin.link) {
|
||||
args.admin.link = {}
|
||||
}
|
||||
if (!args.admin.link.fields) {
|
||||
args.admin.link.fields = []
|
||||
}
|
||||
args.admin.link.fields = await sanitizeFields({
|
||||
config: config as unknown as Config,
|
||||
fields: transformExtraFields(args.admin?.link?.fields, config),
|
||||
validRelationships,
|
||||
})
|
||||
|
||||
if (args?.admin?.upload?.collections) {
|
||||
for (const collection of Object.keys(args.admin.upload.collections)) {
|
||||
if (args?.admin?.upload?.collections[collection]?.fields) {
|
||||
args.admin.upload.collections[collection].fields = await sanitizeFields({
|
||||
config: config as unknown as Config,
|
||||
fields: args.admin?.upload?.collections[collection]?.fields,
|
||||
validRelationships,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
populationPromises({
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
field,
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
siblingDoc,
|
||||
}) {
|
||||
if (
|
||||
field.admin?.elements?.includes('relationship') ||
|
||||
field.admin?.elements?.includes('upload') ||
|
||||
field.admin?.elements?.includes('link') ||
|
||||
!field?.admin?.elements
|
||||
) {
|
||||
richTextRelationshipPromise({
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
field,
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
siblingDoc,
|
||||
})
|
||||
}
|
||||
},
|
||||
validate: richTextValidate,
|
||||
}
|
||||
|
||||
return {
|
||||
CellComponent: RichTextCell,
|
||||
FieldComponent: RichTextField,
|
||||
generateComponentMap: getGenerateComponentMap(args),
|
||||
generateSchemaMap: getGenerateSchemaMap(args),
|
||||
outputSchema: ({ isRequired }) => {
|
||||
return {
|
||||
type: withNullableJSONSchemaType('array', isRequired),
|
||||
items: {
|
||||
type: 'object',
|
||||
},
|
||||
}
|
||||
},
|
||||
populationPromises({
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
field,
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
siblingDoc,
|
||||
}) {
|
||||
if (
|
||||
field.admin?.elements?.includes('relationship') ||
|
||||
field.admin?.elements?.includes('upload') ||
|
||||
field.admin?.elements?.includes('link') ||
|
||||
!field?.admin?.elements
|
||||
) {
|
||||
richTextRelationshipPromise({
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
field,
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
siblingDoc,
|
||||
})
|
||||
}
|
||||
},
|
||||
validate: richTextValidate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
import type { Config, SanitizedConfig } from 'payload/config'
|
||||
import type { Field, RichTextFieldProps } from 'payload/types'
|
||||
import type { Editor } from 'slate'
|
||||
|
||||
@@ -58,9 +57,7 @@ export type AdapterArguments = {
|
||||
hideGutter?: boolean
|
||||
leaves?: RichTextLeaf[]
|
||||
link?: {
|
||||
fields?:
|
||||
| ((args: { config: SanitizedConfig; defaultFields: Field[]; i18n: I18n }) => Field[])
|
||||
| Field[]
|
||||
fields?: ((args: { config: SanitizedConfig; defaultFields: Field[] }) => Field[]) | Field[]
|
||||
}
|
||||
placeholder?: Record<string, string> | string
|
||||
rtl?: boolean
|
||||
|
||||
Reference in New Issue
Block a user