From d411874589d52f4c9c00a823927cda88e0a2149f Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 13 Oct 2023 20:02:18 +0200 Subject: [PATCH] chore(richtext-lexical): Blocks: clean up population --- .../field/features/Blocks/afterReadPromise.ts | 45 +-- .../src/field/features/Blocks/validate.ts | 8 +- test/fields/collections/Lexical/blocks.ts | 11 + .../Lexical/generateLexicalRichText.ts | 323 ++---------------- test/fields/collections/Lexical/index.ts | 4 +- test/fields/config.ts | 4 +- 6 files changed, 68 insertions(+), 327 deletions(-) diff --git a/packages/richtext-lexical/src/field/features/Blocks/afterReadPromise.ts b/packages/richtext-lexical/src/field/features/Blocks/afterReadPromise.ts index 74566f7626..c63d88b768 100644 --- a/packages/richtext-lexical/src/field/features/Blocks/afterReadPromise.ts +++ b/packages/richtext-lexical/src/field/features/Blocks/afterReadPromise.ts @@ -1,3 +1,5 @@ +import type { Block } from 'payload/types' + import { sanitizeFields } from 'payload/config' import type { BlocksFeatureProps } from '.' @@ -20,40 +22,41 @@ export const blockAfterReadPromiseHOC = ( showHiddenFields, siblingDoc, }) => { + const blocks: Block[] = props.blocks + const blockFieldData = node.fields.data + const promises: Promise[] = [] // Sanitize block's fields here. This is done here and not in the feature, because the payload config is available here const payloadConfig = req.payload.config const validRelationships = payloadConfig.collections.map((c) => c.slug) || [] - props.blocks = props.blocks.map((block) => { - const unsanitizedBlock = { ...block } - unsanitizedBlock.fields = sanitizeFields({ + blocks.forEach((block) => { + block.fields = sanitizeFields({ config: payloadConfig, fields: block.fields, validRelationships, }) - return unsanitizedBlock }) - if (Array.isArray(props.blocks)) { - props.blocks.forEach((block) => { - if (block?.fields) { - recurseNestedFields({ - afterReadPromises, - currentDepth, - data: node.fields.data || {}, - depth, - fields: block.fields, - overrideAccess, - promises, - req, - showHiddenFields, - siblingDoc, - }) - } - }) + // find block used in this node + const block = props.blocks.find((block) => block.slug === blockFieldData.blockType) + if (!block || !block?.fields?.length || !blockFieldData) { + return promises } + recurseNestedFields({ + afterReadPromises, + currentDepth, + data: blockFieldData, + depth, + fields: block.fields, + overrideAccess, + promises, + req, + showHiddenFields, + siblingDoc, + }) + return promises } diff --git a/packages/richtext-lexical/src/field/features/Blocks/validate.ts b/packages/richtext-lexical/src/field/features/Blocks/validate.ts index 1a2ca54b07..56f3a6801c 100644 --- a/packages/richtext-lexical/src/field/features/Blocks/validate.ts +++ b/packages/richtext-lexical/src/field/features/Blocks/validate.ts @@ -15,12 +15,12 @@ export const blockValidationHOC = ( payloadConfig, validation, }) => { - const blockFieldValues = node.fields.data - + const blockFieldData = node.fields.data const blocks: Block[] = props.blocks + // Sanitize block's fields here. This is done here and not in the feature, because the payload config is available here + const validRelationships = payloadConfig.collections.map((c) => c.slug) || [] blocks.forEach((block) => { - const validRelationships = payloadConfig.collections.map((c) => c.slug) || [] block.fields = sanitizeFields({ config: payloadConfig, fields: block.fields, @@ -29,7 +29,7 @@ export const blockValidationHOC = ( }) // find block - const block = props.blocks.find((block) => block.slug === blockFieldValues.blockType) + const block = props.blocks.find((block) => block.slug === blockFieldData.blockType) // validate block if (!block) { diff --git a/test/fields/collections/Lexical/blocks.ts b/test/fields/collections/Lexical/blocks.ts index ddc80b9a77..6b04794cda 100644 --- a/test/fields/collections/Lexical/blocks.ts +++ b/test/fields/collections/Lexical/blocks.ts @@ -13,6 +13,17 @@ export const TextBlock: Block = { slug: 'text', } +export const RichTextBlock: Block = { + fields: [ + { + name: 'richText', + type: 'richText', + editor: lexicalEditor(), + }, + ], + slug: 'richText', +} + export const UploadAndRichTextBlock: Block = { fields: [ { diff --git a/test/fields/collections/Lexical/generateLexicalRichText.ts b/test/fields/collections/Lexical/generateLexicalRichText.ts index f98bbbbf9c..0aef6a87ac 100644 --- a/test/fields/collections/Lexical/generateLexicalRichText.ts +++ b/test/fields/collections/Lexical/generateLexicalRichText.ts @@ -1,5 +1,3 @@ -import { loremIpsum } from './loremIpsum' - export function generateLexicalRichText() { return { root: { @@ -9,312 +7,39 @@ export function generateLexicalRichText() { version: 1, children: [ { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: "Hello, I'm a rich text field.", - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: 'center', - indent: 0, - type: 'heading', - version: 1, - tag: 'h1', - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'I can do all kinds of fun stuff like ', - type: 'text', - version: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'render links', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'link', - version: 1, - fields: { - url: 'https://payloadcms.com', - newTab: true, - linkType: 'custom', - }, - }, - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: ', ', - type: 'text', - version: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'link to relationships', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'link', - version: 1, - fields: { - url: 'https://', - doc: { - value: { - id: '{{ARRAY_DOC_ID}}', - }, - relationTo: 'array-fields', - }, - newTab: false, - linkType: 'internal', - }, - }, - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: ', and store nested relationship fields:', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', format: '', - indent: 0, - type: 'paragraph', + type: 'block', version: 1, - }, - { - format: '', - type: 'relationship', - version: 1, - value: { - id: '{{TEXT_DOC_ID}}', - }, - relationTo: 'text-fields', - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'You can build your own elements, too.', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - }, - { - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: "It's built with Lexical", - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'listitem', - version: 1, - value: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'It stores content as JSON so you can use it wherever you need', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'listitem', - version: 1, - value: 2, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: "It's got a great editing experience for non-technical users", - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'listitem', - version: 1, - value: 3, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'list', - version: 1, - listType: 'bullet', - start: 1, - tag: 'ul', - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'And a whole lot more.', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - }, - { - format: '', - type: 'upload', - version: 1, - relationTo: 'uploads', - value: { - id: '{{UPLOAD_DOC_ID}}', - }, fields: { - caption: { - root: { - type: 'root', - format: '', - indent: 0, - version: 1, - children: [ - ...[...Array(4)].map(() => ({ - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: loremIpsum, - type: 'text', - version: 1, + data: { + id: '65298129c06820f57f482ab8', + richText: { + root: { + type: 'root', + format: '', + indent: 0, + version: 1, + children: [ + { + format: '', + type: 'relationship', + version: 1, + relationTo: 'text-fields', + value: { + id: '{{TEXT_DOC_ID}}', }, - ], - })), - ], - direction: 'ltr', + }, + ], + direction: null, + }, }, + blockName: 'blocky', + blockType: 'richText', }, }, }, - { - children: [], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - }, ], - direction: 'ltr', + direction: null, }, } } diff --git a/test/fields/collections/Lexical/index.ts b/test/fields/collections/Lexical/index.ts index 33b3bd8580..5fadb7f9c4 100644 --- a/test/fields/collections/Lexical/index.ts +++ b/test/fields/collections/Lexical/index.ts @@ -9,6 +9,7 @@ import { } from '../../../../packages/richtext-lexical/src' import { RelationshipBlock, + RichTextBlock, SelectFieldBlock, SubBlockBlock, TextBlock, @@ -68,6 +69,7 @@ export const LexicalFields: CollectionConfig = { }), BlocksFeature({ blocks: [ + RichTextBlock, TextBlock, UploadAndRichTextBlock, SelectFieldBlock, @@ -81,7 +83,7 @@ export const LexicalFields: CollectionConfig = { ], } -export const lexicalRichTextDoc = { +export const LexicalRichTextDoc = { title: 'Rich Text', richTextLexicalCustomFields: generateLexicalRichText(), } diff --git a/test/fields/config.ts b/test/fields/config.ts index 7c58f78cb2..fa64a5d926 100644 --- a/test/fields/config.ts +++ b/test/fields/config.ts @@ -14,7 +14,7 @@ import DateFields, { dateDoc } from './collections/Date' import GroupFields, { groupDoc } from './collections/Group' import IndexedFields from './collections/Indexed' import JSONFields, { jsonDoc } from './collections/JSON' -import { LexicalFields } from './collections/Lexical' +import { LexicalFields, LexicalRichTextDoc } from './collections/Lexical' import NumberFields, { numberDoc } from './collections/Number' import PointFields, { pointDoc } from './collections/Point' import RadioFields, { radiosDoc } from './collections/Radio' @@ -150,7 +150,7 @@ export default buildConfigWithDefaults({ ) const lexicalRichTextDocWithRelId = JSON.parse( - JSON.stringify(richTextDoc) + JSON.stringify(LexicalRichTextDoc) .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, formattedID) .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, formattedJPGID) .replace(/"\{\{TEXT_DOC_ID\}\}"/g, formattedTextID),