From 2486c7dba099fbff4ebde4a59d483e42f1dc2cd5 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Thu, 11 Apr 2024 16:42:35 -0400 Subject: [PATCH 1/2] fix(richtext-lexical): incorrect margin for nested unordered lists --- .../richtext-lexical/src/field/lexical/theme/EditorTheme.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/richtext-lexical/src/field/lexical/theme/EditorTheme.scss b/packages/richtext-lexical/src/field/lexical/theme/EditorTheme.scss index dca9cb358..f6e4cbb8c 100644 --- a/packages/richtext-lexical/src/field/lexical/theme/EditorTheme.scss +++ b/packages/richtext-lexical/src/field/lexical/theme/EditorTheme.scss @@ -331,6 +331,10 @@ list-style-position: inside; } + &__ul ul { + margin: 0; + } + &__listItem { margin: 0 0px 0.4em 16px; } From cb4214fe6e9df4dd05d71dd2478edcd15e450f50 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 12 Apr 2024 11:58:05 -0400 Subject: [PATCH 2/2] fix(richtext-lexical)!: fix output of internal list HTML converter BREAKING: Changes the classnames of the converted HTML --- docs/rich-text/lexical.mdx | 13 ++++++++++ .../features/converters/html/field/index.ts | 19 ++++++++++---- .../src/field/features/lists/htmlConverter.ts | 26 ++++++++++++++----- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/docs/rich-text/lexical.mdx b/docs/rich-text/lexical.mdx index 4a4367ab8..02c56417c 100644 --- a/docs/rich-text/lexical.mdx +++ b/docs/rich-text/lexical.mdx @@ -234,6 +234,19 @@ This method employs `convertLexicalToHTML` from `@payloadcms/richtext-lexical`, Because every `Feature` is able to provide html converters, and because the `htmlFeature` can modify those or provide their own, we need to consolidate them with the default html Converters using the `consolidateHTMLConverters` function. +#### CSS + +Payload's lexical HTML converter does not generate CSS for you, but it does add classes to the generated HTML. You can use these classes to style the HTML in your frontend. + +Here is some "base" CSS you can use to ensure that nested lists render correctly: + +```css +/* Base CSS for Lexical HTML */ +.nestedListItem, .list-check { + list-style-type: none; +} +``` + #### Creating your own HTML Converter HTML Converters are typed as `HTMLConverter`, which contains the node type it should handle, and a function that accepts the serialized node from the lexical editor, and outputs the HTML string. Here's the HTML Converter of the Upload node as an example: diff --git a/packages/richtext-lexical/src/field/features/converters/html/field/index.ts b/packages/richtext-lexical/src/field/features/converters/html/field/index.ts index ad3d97cc2..4b2369909 100644 --- a/packages/richtext-lexical/src/field/features/converters/html/field/index.ts +++ b/packages/richtext-lexical/src/field/features/converters/html/field/index.ts @@ -1,5 +1,5 @@ import type { SerializedEditorState } from 'lexical' -import type { Field, RichTextField, TextField } from 'payload/types' +import type { Field, RichTextField } from 'payload/types' import type { AdapterProps, LexicalRichTextAdapter } from '../../../../../types.js' import type { SanitizedServerEditorConfig } from '../../../../lexical/config/types.js' @@ -10,6 +10,12 @@ import { defaultHTMLConverters } from '../converter/defaultConverters.js' import { convertLexicalToHTML } from '../converter/index.js' type Props = { + /** + * Whether the lexicalHTML field should be hidden in the admin panel + * + * @default true + */ + hidden?: boolean name: string } @@ -53,13 +59,16 @@ export const lexicalHTML: ( **/ lexicalFieldName: string, props: Props, -) => TextField = (lexicalFieldName, props) => { - const { name = 'lexicalHTML' } = props +) => Field = (lexicalFieldName, props) => { + const { name = 'lexicalHTML', hidden = true } = props return { name, - type: 'text', + type: 'code', admin: { - hidden: true, + editorOptions: { + language: 'html', + }, + hidden, }, hooks: { afterRead: [ diff --git a/packages/richtext-lexical/src/field/features/lists/htmlConverter.ts b/packages/richtext-lexical/src/field/features/lists/htmlConverter.ts index 490b57b5a..8e197c09c 100644 --- a/packages/richtext-lexical/src/field/features/lists/htmlConverter.ts +++ b/packages/richtext-lexical/src/field/features/lists/htmlConverter.ts @@ -1,6 +1,7 @@ import type { SerializedListItemNode, SerializedListNode } from '@lexical/list' import lexicalListImport from '@lexical/list' +import { v4 as uuidv4 } from 'uuid' const { ListItemNode, ListNode } = lexicalListImport import type { HTMLConverter } from '../converters/html/converter/types.js' @@ -19,13 +20,15 @@ export const ListHTMLConverter: HTMLConverter = { payload, }) - return `<${node?.tag} class="${node?.listType}">${childrenText}` + return `<${node?.tag} class="list-${node?.listType}">${childrenText}` }, nodeTypes: [ListNode.getType()], } export const ListItemHTMLConverter: HTMLConverter = { converter: async ({ converters, node, parent, payload }) => { + const hasSubLists = node.children.some((child) => child.type === 'list') + const childrenText = await convertLexicalNodesToHTML({ converters, lexicalNodes: node.children, @@ -37,19 +40,30 @@ export const ListItemHTMLConverter: HTMLConverter = { }) if ('listType' in parent && parent?.listType === 'check') { + const uuid = uuidv4() + return `` } else { - return `
  • ${childrenText}
  • ` + return `
  • ${childrenText}
  • ` } }, nodeTypes: [ListItemNode.getType()],