fix(richtext-lexical): various issues for lexical sub-fields due to incorrectly generated client field schema map (#10276)
Fixes https://github.com/payloadcms/payload/issues/9905, https://github.com/payloadcms/payload/issues/9660 Single lexical fields were represented file in the schema map (`path => field`). In the client schema map however, they were incorrectly represented like this: `path => { fields: [field] } `
This commit is contained in:
@@ -30,6 +30,10 @@ export const RscEntryLexicalField: React.FC<
|
||||
const path = args.path ?? (args.clientField as RichTextFieldClient).name
|
||||
const schemaPath = args.schemaPath ?? path
|
||||
|
||||
if (!(args?.clientField as RichTextFieldClient)?.name) {
|
||||
throw new Error('Initialized lexical RSC field without a field name')
|
||||
}
|
||||
|
||||
const { clientFeatures, featureClientSchemaMap } = initLexicalFeatures({
|
||||
clientFieldSchemaMap: args.clientFieldSchemaMap,
|
||||
fieldSchemaMap: args.fieldSchemaMap,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
type ClientField,
|
||||
type ClientFieldSchemaMap,
|
||||
createClientFields,
|
||||
type Field,
|
||||
type FieldSchemaMap,
|
||||
type Payload,
|
||||
} from 'payload'
|
||||
@@ -108,16 +109,25 @@ export const traverseFields = ({
|
||||
|
||||
// Now loop through them, convert each entry to a client field and add it to the client schema map
|
||||
for (const [path, subField] of richTextFieldSchemaMap.entries()) {
|
||||
// check if fields is the only key in the subField object
|
||||
const isFieldsOnly = Object.keys(subField).length === 1 && 'fields' in subField
|
||||
|
||||
const clientFields = createClientFields({
|
||||
defaultIDType: payload.config.db.defaultIDType,
|
||||
disableAddingID: true,
|
||||
fields: 'fields' in subField ? subField.fields : [subField],
|
||||
fields: isFieldsOnly ? subField.fields : [subField as Field],
|
||||
i18n,
|
||||
importMap: payload.importMap,
|
||||
})
|
||||
clientSchemaMap.set(path, {
|
||||
fields: clientFields,
|
||||
})
|
||||
|
||||
clientSchemaMap.set(
|
||||
path,
|
||||
isFieldsOnly
|
||||
? {
|
||||
fields: clientFields,
|
||||
}
|
||||
: clientFields[0],
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1174,5 +1174,25 @@ describe('lexicalBlocks', () => {
|
||||
expect(height2).toBe(74)
|
||||
}).toPass()
|
||||
})
|
||||
|
||||
test('ensure nested lexical field displays field label and description', async () => {
|
||||
// Previously, we had the issue that nested lexical fields did not display the field label and description, as
|
||||
// their client field configs were generated incorrectly on the server.
|
||||
await page.goto('http://localhost:3000/admin/collections/LexicalInBlock?limit=10')
|
||||
await page.locator('.cell-id a').first().click()
|
||||
await page.waitForURL(`**/collections/LexicalInBlock/**`)
|
||||
|
||||
await expect(
|
||||
page.locator('.lexical-block-blockInLexical .render-fields label.field-label'),
|
||||
).toHaveText('My Label*')
|
||||
await expect(
|
||||
page.locator('.lexical-block-blockInLexical .render-fields .required'),
|
||||
).toHaveText('*')
|
||||
await expect(
|
||||
page.locator(
|
||||
'.lexical-block-blockInLexical .render-fields .field-description-lexicalInBlock',
|
||||
),
|
||||
).toHaveText('Some Description')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { BlocksFeature, lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export const LexicalInBlock: CollectionConfig = {
|
||||
slug: 'LexicalInBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({
|
||||
features: [
|
||||
BlocksFeature({
|
||||
blocks: [
|
||||
{
|
||||
slug: 'blockInLexical',
|
||||
fields: [
|
||||
{
|
||||
name: 'lexicalInBlock',
|
||||
label: 'My Label',
|
||||
type: 'richText',
|
||||
required: true,
|
||||
editor: lexicalEditor(),
|
||||
admin: {
|
||||
description: 'Some Description',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
|
||||
@@ -412,6 +412,21 @@ export interface User {
|
||||
*/
|
||||
export interface LexicalInBlock {
|
||||
id: string;
|
||||
content?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: string;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
blocks?:
|
||||
| {
|
||||
lexical?: {
|
||||
@@ -2041,6 +2056,7 @@ export interface UsersSelect<T extends boolean = true> {
|
||||
* via the `definition` "LexicalInBlock_select".
|
||||
*/
|
||||
export interface LexicalInBlockSelect<T extends boolean = true> {
|
||||
content?: T;
|
||||
blocks?:
|
||||
| T
|
||||
| {
|
||||
|
||||
@@ -481,6 +481,28 @@ export const seed = async (_payload: Payload) => {
|
||||
await _payload.create({
|
||||
collection: 'LexicalInBlock',
|
||||
data: {
|
||||
content: {
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
format: '',
|
||||
type: 'block',
|
||||
version: 2,
|
||||
fields: {
|
||||
id: '6773773284be8978db7a498d',
|
||||
lexicalInBlock: textToLexicalJSON({ text: 'text' }),
|
||||
blockName: '',
|
||||
blockType: 'blockInLexical',
|
||||
},
|
||||
},
|
||||
],
|
||||
direction: null,
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
blockType: 'lexicalInBlock2',
|
||||
|
||||
Reference in New Issue
Block a user