From 179d808d72909fd48b96c85ced18c7177235c479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:07:52 -0300 Subject: [PATCH 1/4] docs: update Lexical to JSX documentation for RichText component --- docs/lexical/converters.mdx | 12 ++++++++---- .../react/components/RichText/index.tsx | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/docs/lexical/converters.mdx b/docs/lexical/converters.mdx index da191ed05d5..a9409b00154 100644 --- a/docs/lexical/converters.mdx +++ b/docs/lexical/converters.mdx @@ -10,20 +10,24 @@ Lexical saves data in JSON - this is great for storage and flexibility and allow ## Lexical => JSX -If you have a React-based frontend, converting lexical to JSX is the recommended way to render rich text content in your frontend. To do that, import the `RichText` component from `@payloadcms/richtext-lexical/react` and pass the lexical content to it: +If your frontend uses React, converting Lexical to JSX is the recommended way to render rich text content. Import the `RichText` component from `@payloadcms/richtext-lexical/react` and pass the Lexical content to it: ```tsx import React from 'react' import { RichText } from '@payloadcms/richtext-lexical/react' +import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical' -export const MyComponent = ({ lexicalData }) => { +export const MyComponent = ({ data }: { data: SerializedEditorState }) => { return ( - + ) } ``` -The `RichText` component will come with the most common serializers built-in, though you can also pass in your own serializers if you need to. +The `RichText` component includes built-in serializers for common Lexical nodes but allows customization through the `converters` prop. + +In our website template [you have an example](https://github.com/payloadcms/payload/blob/main/templates/website/src/components/RichText/index.tsx) of how to use `converters` to render custom blocks. + The JSX converter expects the input data to be fully populated. When fetching data, ensure the `depth` setting is high enough, to ensure that lexical nodes such as uploads are populated. diff --git a/packages/richtext-lexical/src/exports/react/components/RichText/index.tsx b/packages/richtext-lexical/src/exports/react/components/RichText/index.tsx index 82cb2adbb97..0aceb3b6f76 100644 --- a/packages/richtext-lexical/src/exports/react/components/RichText/index.tsx +++ b/packages/richtext-lexical/src/exports/react/components/RichText/index.tsx @@ -20,15 +20,30 @@ export type JSXConvertersFunction< | SerializedInlineBlockNode<{ blockName?: null | string; blockType: string }>, > = (args: { defaultConverters: JSXConverters }) => JSXConverters -type Props = { +type RichTextProps = { + /** + * Additional class names for the container. + */ className?: string + /** + * Custom converters to transform your nodes to JSX. Can be an object or a function that receives the default converters. + */ converters?: JSXConverters | JSXConvertersFunction + /** + * Serialized editor state to render. + */ data: SerializedEditorState + /** + * If true, disables indentation globally. If an array, disables for specific node `type` values. + */ disableIndent?: boolean | string[] + /** + * If true, disables text alignment globally. If an array, disables for specific node `type` values. + */ disableTextAlign?: boolean | string[] } -export const RichText: React.FC = ({ +export const RichText: React.FC = ({ className, converters, data: editorState, From 3525b1677bee27a93a94796c966e3df15433ecca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:27:10 -0300 Subject: [PATCH 2/4] move lexical/overview to rich-text/overview --- docs/lexical/overview.mdx | 292 ------------------------------------ docs/rich-text/overview.mdx | 292 ++++++++++++++++++++++++++++++++++-- 2 files changed, 283 insertions(+), 301 deletions(-) delete mode 100644 docs/lexical/overview.mdx diff --git a/docs/lexical/overview.mdx b/docs/lexical/overview.mdx deleted file mode 100644 index c11561fce61..00000000000 --- a/docs/lexical/overview.mdx +++ /dev/null @@ -1,292 +0,0 @@ ---- -title: Lexical Overview -label: Overview -order: 10 -desc: Built by Meta, Lexical is an incredibly powerful rich text editor, and it works beautifully within Payload. -keywords: lexical, rich text, editor, headless cms ---- - -One of Payload's goals is to build the best rich text editor experience that we possibly can. We want to combine the beauty and polish of the Medium editing experience with the strength and features of the Notion editor - all in one place. - -Classically, we've used SlateJS to work toward this goal, but building custom elements into Slate has proven to be more difficult than we'd like, and we've been keeping our options open. - -Lexical is extremely impressive and trivializes a lot of the hard parts of building new elements into a rich text editor. It has a few distinct advantages over Slate, including the following: - -1. A "/" menu, which allows editors to easily add new elements while never leaving their keyboard -1. A "hover" toolbar that pops up if you select text -1. It supports Payload blocks natively, directly within your rich text editor -1. Custom elements, called "features", are much easier to build in Lexical vs. Slate - -To use the Lexical editor, first you need to install it: - -``` -npm install @payloadcms/richtext-lexical -``` - -Once you have it installed, you can pass it to your top-level Payload Config as follows: - -```ts -import { buildConfig } from 'payload' -import { lexicalEditor } from '@payloadcms/richtext-lexical' - -export default buildConfig({ - collections: [ - // your collections here - ], - // Pass the Lexical editor to the root config - editor: lexicalEditor({}), -}) -``` - -You can also override Lexical settings on a field-by-field basis as follows: - -```ts -import type { CollectionConfig } from 'payload' -import { lexicalEditor } from '@payloadcms/richtext-lexical' - -export const Pages: CollectionConfig = { - slug: 'pages', - fields: [ - { - name: 'content', - type: 'richText', - // Pass the Lexical editor here and override base settings as necessary - editor: lexicalEditor({}), - }, - ], -} -``` - -## Extending the lexical editor with Features - -Lexical has been designed with extensibility in mind. Whether you're aiming to introduce new functionalities or tweak the existing ones, Lexical makes it seamless for you to bring those changes to life. - -### Features: The Building Blocks - -At the heart of Lexical's customization potential are "features". While Lexical ships with a set of default features we believe are essential for most use cases, the true power lies in your ability to redefine, expand, or prune these as needed. - -If you remove all the default features, you're left with a blank editor. You can then add in only the features you need, or you can build your own custom features from scratch. - -### Integrating New Features - -To weave in your custom features, utilize the `features` prop when initializing the Lexical Editor. Here's a basic example of how this is done: - -```ts -import { - BlocksFeature, - LinkFeature, - UploadFeature, - lexicalEditor, -} from '@payloadcms/richtext-lexical' -import { Banner } from '../blocks/Banner' -import { CallToAction } from '../blocks/CallToAction' - -{ - editor: lexicalEditor({ - features: ({ defaultFeatures, rootFeatures }) => [ - ...defaultFeatures, - LinkFeature({ - // Example showing how to customize the built-in fields - // of the Link feature - fields: ({ defaultFields }) => [ - ...defaultFields, - { - name: 'rel', - label: 'Rel Attribute', - type: 'select', - hasMany: true, - options: ['noopener', 'noreferrer', 'nofollow'], - admin: { - description: - 'The rel attribute defines the relationship between a linked resource and the current document. This is a custom link field.', - }, - }, - ], - }), - UploadFeature({ - collections: { - uploads: { - // Example showing how to customize the built-in fields - // of the Upload feature - fields: [ - { - name: 'caption', - type: 'richText', - editor: lexicalEditor(), - }, - ], - }, - }, - }), - // This is incredibly powerful. You can re-use your Payload blocks - // directly in the Lexical editor as follows: - BlocksFeature({ - blocks: [Banner, CallToAction], - }), - ], - }) -} -``` - -`features` can be both an array of features, or a function returning an array of features. The function provides the following props: - - -| Prop | Description | -|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **`defaultFeatures`** | This opinionated array contains all "recommended" default features. You can see which features are included in the default features in the table below. | -| **`rootFeatures`** | This array contains all features that are enabled in the root richText editor (the one defined in the payload.config.ts). If this field is the root richText editor, or if the root richText editor is not a lexical editor, this array will be empty. | - - -## Features overview - -Here's an overview of all the included features: - -| Feature Name | Included by default | Description | -|---------------------------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **`BoldTextFeature`** | Yes | Handles the bold text format | -| **`ItalicTextFeature`** | Yes | Handles the italic text format | -| **`UnderlineTextFeature`** | Yes | Handles the underline text format | -| **`StrikethroughTextFeature`** | Yes | Handles the strikethrough text format | -| **`SubscriptTextFeature`** | Yes | Handles the subscript text format | -| **`SuperscriptTextFeature`** | Yes | Handles the superscript text format | -| **`InlineCodeTextFeature`** | Yes | Handles the inline-code text format | -| **`ParagraphFeature`** | Yes | Handles paragraphs. Since they are already a key feature of lexical itself, this Feature mainly handles the Slash and Add-Block menu entries for paragraphs | -| **`HeadingFeature`** | Yes | Adds Heading Nodes (by default, H1 - H6, but that can be customized) | -| **`AlignFeature`** | Yes | Allows you to align text left, centered and right | -| **`IndentFeature`** | Yes | Allows you to indent text with the tab key | -| **`UnorderedListFeature`** | Yes | Adds unordered lists (ul) | -| **`OrderedListFeature`** | Yes | Adds ordered lists (ol) | -| **`CheckListFeature`** | Yes | Adds checklists | -| **`LinkFeature`** | Yes | Allows you to create internal and external links | -| **`RelationshipFeature`** | Yes | Allows you to create block-level (not inline) relationships to other documents | -| **`BlockQuoteFeature`** | Yes | Allows you to create block-level quotes | -| **`UploadFeature`** | Yes | Allows you to create block-level upload nodes - this supports all kinds of uploads, not just images | -| **`HorizontalRuleFeature`** | Yes | Horizontal rules / separators. Basically displays an `
` element | -| **`InlineToolbarFeature`** | Yes | The inline toolbar is the floating toolbar which appears when you select text. This toolbar only contains actions relevant for selected text | -| **`FixedToolbarFeature`** | No | This classic toolbar is pinned to the top and always visible. Both inline and fixed toolbars can be enabled at the same time. | -| **`BlocksFeature`** | No | Allows you to use Payload's [Blocks Field](/docs/fields/blocks) directly inside your editor. In the feature props, you can specify the allowed blocks - just like in the Blocks field. | -| **`TreeViewFeature`** | No | Adds a debug box under the editor, which allows you to see the current editor state live, the dom, as well as time travel. Very useful for debugging | -| **`EXPERIMENTAL_TableFeature`** | No | Adds support for tables. This feature may be removed or receive breaking changes in the future - even within a stable lexical release, without needing a major release. | - -Notice how even the toolbars are features? That's how extensible our lexical editor is - you could theoretically create your own toolbar if you wanted to! - -## Creating your own, custom Feature - -You can find more information about creating your own feature in our [building custom feature docs](/docs/lexical/building-custom-features). - -## TypeScript - -Every single piece of saved data is 100% fully-typed within lexical. It provides a type for every single node, which can be imported from `@payloadcms/richtext-lexical` - each type is prefixed with `Serialized`, e.g. `SerializedUploadNode`. - -In order to fully type the entire editor JSON, you can use our `TypedEditorState` helper type, which accepts a union of all possible node types as a generic. The reason we do not provide a type which already contains all possible node types is because the possible node types depend on which features you have enabled in your editor. Here is an example: - -```ts -import type { - SerializedAutoLinkNode, - SerializedBlockNode, - SerializedHorizontalRuleNode, - SerializedLinkNode, - SerializedListItemNode, - SerializedListNode, - SerializedParagraphNode, - SerializedQuoteNode, - SerializedRelationshipNode, - SerializedTextNode, - SerializedUploadNode, - TypedEditorState, - SerializedHeadingNode, -} from '@payloadcms/richtext-lexical' - -const editorState: TypedEditorState< - | SerializedAutoLinkNode - | SerializedBlockNode - | SerializedHorizontalRuleNode - | SerializedLinkNode - | SerializedListItemNode - | SerializedListNode - | SerializedParagraphNode - | SerializedQuoteNode - | SerializedRelationshipNode - | SerializedTextNode - | SerializedUploadNode - | SerializedHeadingNode -> = { - root: { - type: 'root', - direction: 'ltr', - format: '', - indent: 0, - version: 1, - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'Some text. Every property here is fully-typed', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - textFormat: 0, - version: 1, - }, - ], - }, -} -``` - -Alternatively, you can use the `DefaultTypedEditorState` type, which includes all types for all nodes included in the `defaultFeatures`: - -```ts -import type { - DefaultTypedEditorState -} from '@payloadcms/richtext-lexical' - -const editorState: DefaultTypedEditorState = { - root: { - type: 'root', - direction: 'ltr', - format: '', - indent: 0, - version: 1, - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'Some text. Every property here is fully-typed', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - textFormat: 0, - version: 1, - }, - ], - }, -} -``` - -Just like `TypedEditorState`, the `DefaultTypedEditorState` also accepts an optional node type union as a generic. Here, this would **add** the specified node types to the default ones. Example: `DefaultTypedEditorState`. - -This is a type-safe representation of the editor state. Looking at the auto-suggestions of `type` it will show you all the possible node types you can use. - -Make sure to only use types exported from `@payloadcms/richtext-lexical`, not from the lexical core packages. We only have control over types we export and can guarantee that those are correct, even though lexical core may export types with identical names. - -### Automatic type generation - -Lexical does not generate the accurate type definitions for your richText fields for you yet - this will be improved in the future. Currently, it only outputs the rough shape of the editor JSON which you can enhance using type assertions. diff --git a/docs/rich-text/overview.mdx b/docs/rich-text/overview.mdx index 0ee2888fb6a..464ffa4628c 100644 --- a/docs/rich-text/overview.mdx +++ b/docs/rich-text/overview.mdx @@ -1,18 +1,292 @@ --- -title: Overview +title: Rich Text Editor Overview label: Overview order: 10 -desc: Rich Text within Payload is extremely powerful. We've combined the beauty of the Medium editor with the power of the Notion editor all in one place. -keywords: slatejs, lexical, rich text, json, custom editor, javascript, typescript +desc: The Payload editor, based on Lexical, allows for great customization with unparalleled ease. +keywords: lexical, rich text, editor, headless cms --- -Payload currently supports two official rich text editors and you can choose either one depending on your needs. +One of Payload's goals is to build the best rich text editor experience that we possibly can. We want to combine the beauty and polish of the Medium editing experience with the strength and features of the Notion editor - all in one place. -1. [SlateJS](/docs/rich-text/slate) - stable, backwards-compatible with 1.0 -2. [Lexical](/docs/lexical/overview) - recommended +Classically, we've used SlateJS to work toward this goal, but building custom elements into Slate has proven to be more difficult than we'd like, and we've been keeping our options open. -These editors are built on an "adapter pattern" which means that you will need to install the editor you'd like to use. Take a look at the docs for the editor you'd like to use for instructions on how to install it. +Lexical is extremely impressive and trivializes a lot of the hard parts of building new elements into a rich text editor. It has a few distinct advantages over Slate, including the following: -The big TL;DR here is that Slate is what we have used in the past, and we still support it for existing projects, but if you're building something new and you're feeling adventurous, you should give Lexical a shot. Slate has a lot of good stuff, but Lexical has lots more. +1. A "/" menu, which allows editors to easily add new elements while never leaving their keyboard +1. A "hover" toolbar that pops up if you select text +1. It supports Payload blocks natively, directly within your rich text editor +1. Custom elements, called "features", are much easier to build in Lexical vs. Slate -No matter which editor you use, you have to install it at the top-level on the `config.editor` property, which will then cascade throughout all of your rich text fields and be used accordingly. Additionally, you also have the option to override the editor on a field-by-field basis if you'd like. +To use the Lexical editor, first you need to install it: + +``` +npm install @payloadcms/richtext-lexical +``` + +Once you have it installed, you can pass it to your top-level Payload Config as follows: + +```ts +import { buildConfig } from 'payload' +import { lexicalEditor } from '@payloadcms/richtext-lexical' + +export default buildConfig({ + collections: [ + // your collections here + ], + // Pass the Lexical editor to the root config + editor: lexicalEditor({}), +}) +``` + +You can also override Lexical settings on a field-by-field basis as follows: + +```ts +import type { CollectionConfig } from 'payload' +import { lexicalEditor } from '@payloadcms/richtext-lexical' + +export const Pages: CollectionConfig = { + slug: 'pages', + fields: [ + { + name: 'content', + type: 'richText', + // Pass the Lexical editor here and override base settings as necessary + editor: lexicalEditor({}), + }, + ], +} +``` + +## Extending the lexical editor with Features + +Lexical has been designed with extensibility in mind. Whether you're aiming to introduce new functionalities or tweak the existing ones, Lexical makes it seamless for you to bring those changes to life. + +### Features: The Building Blocks + +At the heart of Lexical's customization potential are "features". While Lexical ships with a set of default features we believe are essential for most use cases, the true power lies in your ability to redefine, expand, or prune these as needed. + +If you remove all the default features, you're left with a blank editor. You can then add in only the features you need, or you can build your own custom features from scratch. + +### Integrating New Features + +To weave in your custom features, utilize the `features` prop when initializing the Lexical Editor. Here's a basic example of how this is done: + +```ts +import { + BlocksFeature, + LinkFeature, + UploadFeature, + lexicalEditor, +} from '@payloadcms/richtext-lexical' +import { Banner } from '../blocks/Banner' +import { CallToAction } from '../blocks/CallToAction' + +{ + editor: lexicalEditor({ + features: ({ defaultFeatures, rootFeatures }) => [ + ...defaultFeatures, + LinkFeature({ + // Example showing how to customize the built-in fields + // of the Link feature + fields: ({ defaultFields }) => [ + ...defaultFields, + { + name: 'rel', + label: 'Rel Attribute', + type: 'select', + hasMany: true, + options: ['noopener', 'noreferrer', 'nofollow'], + admin: { + description: + 'The rel attribute defines the relationship between a linked resource and the current document. This is a custom link field.', + }, + }, + ], + }), + UploadFeature({ + collections: { + uploads: { + // Example showing how to customize the built-in fields + // of the Upload feature + fields: [ + { + name: 'caption', + type: 'richText', + editor: lexicalEditor(), + }, + ], + }, + }, + }), + // This is incredibly powerful. You can re-use your Payload blocks + // directly in the Lexical editor as follows: + BlocksFeature({ + blocks: [Banner, CallToAction], + }), + ], + }) +} +``` + +`features` can be both an array of features, or a function returning an array of features. The function provides the following props: + + +| Prop | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **`defaultFeatures`** | This opinionated array contains all "recommended" default features. You can see which features are included in the default features in the table below. | +| **`rootFeatures`** | This array contains all features that are enabled in the root richText editor (the one defined in the payload.config.ts). If this field is the root richText editor, or if the root richText editor is not a lexical editor, this array will be empty. | + + +## Features overview + +Here's an overview of all the included features: + +| Feature Name | Included by default | Description | +|---------------------------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **`BoldTextFeature`** | Yes | Handles the bold text format | +| **`ItalicTextFeature`** | Yes | Handles the italic text format | +| **`UnderlineTextFeature`** | Yes | Handles the underline text format | +| **`StrikethroughTextFeature`** | Yes | Handles the strikethrough text format | +| **`SubscriptTextFeature`** | Yes | Handles the subscript text format | +| **`SuperscriptTextFeature`** | Yes | Handles the superscript text format | +| **`InlineCodeTextFeature`** | Yes | Handles the inline-code text format | +| **`ParagraphFeature`** | Yes | Handles paragraphs. Since they are already a key feature of lexical itself, this Feature mainly handles the Slash and Add-Block menu entries for paragraphs | +| **`HeadingFeature`** | Yes | Adds Heading Nodes (by default, H1 - H6, but that can be customized) | +| **`AlignFeature`** | Yes | Allows you to align text left, centered and right | +| **`IndentFeature`** | Yes | Allows you to indent text with the tab key | +| **`UnorderedListFeature`** | Yes | Adds unordered lists (ul) | +| **`OrderedListFeature`** | Yes | Adds ordered lists (ol) | +| **`CheckListFeature`** | Yes | Adds checklists | +| **`LinkFeature`** | Yes | Allows you to create internal and external links | +| **`RelationshipFeature`** | Yes | Allows you to create block-level (not inline) relationships to other documents | +| **`BlockQuoteFeature`** | Yes | Allows you to create block-level quotes | +| **`UploadFeature`** | Yes | Allows you to create block-level upload nodes - this supports all kinds of uploads, not just images | +| **`HorizontalRuleFeature`** | Yes | Horizontal rules / separators. Basically displays an `
` element | +| **`InlineToolbarFeature`** | Yes | The inline toolbar is the floating toolbar which appears when you select text. This toolbar only contains actions relevant for selected text | +| **`FixedToolbarFeature`** | No | This classic toolbar is pinned to the top and always visible. Both inline and fixed toolbars can be enabled at the same time. | +| **`BlocksFeature`** | No | Allows you to use Payload's [Blocks Field](/docs/fields/blocks) directly inside your editor. In the feature props, you can specify the allowed blocks - just like in the Blocks field. | +| **`TreeViewFeature`** | No | Adds a debug box under the editor, which allows you to see the current editor state live, the dom, as well as time travel. Very useful for debugging | +| **`EXPERIMENTAL_TableFeature`** | No | Adds support for tables. This feature may be removed or receive breaking changes in the future - even within a stable lexical release, without needing a major release. | + +Notice how even the toolbars are features? That's how extensible our lexical editor is - you could theoretically create your own toolbar if you wanted to! + +## Creating your own, custom Feature + +You can find more information about creating your own feature in our [building custom feature docs](/docs/lexical/building-custom-features). + +## TypeScript + +Every single piece of saved data is 100% fully-typed within lexical. It provides a type for every single node, which can be imported from `@payloadcms/richtext-lexical` - each type is prefixed with `Serialized`, e.g. `SerializedUploadNode`. + +In order to fully type the entire editor JSON, you can use our `TypedEditorState` helper type, which accepts a union of all possible node types as a generic. The reason we do not provide a type which already contains all possible node types is because the possible node types depend on which features you have enabled in your editor. Here is an example: + +```ts +import type { + SerializedAutoLinkNode, + SerializedBlockNode, + SerializedHorizontalRuleNode, + SerializedLinkNode, + SerializedListItemNode, + SerializedListNode, + SerializedParagraphNode, + SerializedQuoteNode, + SerializedRelationshipNode, + SerializedTextNode, + SerializedUploadNode, + TypedEditorState, + SerializedHeadingNode, +} from '@payloadcms/richtext-lexical' + +const editorState: TypedEditorState< + | SerializedAutoLinkNode + | SerializedBlockNode + | SerializedHorizontalRuleNode + | SerializedLinkNode + | SerializedListItemNode + | SerializedListNode + | SerializedParagraphNode + | SerializedQuoteNode + | SerializedRelationshipNode + | SerializedTextNode + | SerializedUploadNode + | SerializedHeadingNode +> = { + root: { + type: 'root', + direction: 'ltr', + format: '', + indent: 0, + version: 1, + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Some text. Every property here is fully-typed', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + textFormat: 0, + version: 1, + }, + ], + }, +} +``` + +Alternatively, you can use the `DefaultTypedEditorState` type, which includes all types for all nodes included in the `defaultFeatures`: + +```ts +import type { + DefaultTypedEditorState +} from '@payloadcms/richtext-lexical' + +const editorState: DefaultTypedEditorState = { + root: { + type: 'root', + direction: 'ltr', + format: '', + indent: 0, + version: 1, + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'Some text. Every property here is fully-typed', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + textFormat: 0, + version: 1, + }, + ], + }, +} +``` + +Just like `TypedEditorState`, the `DefaultTypedEditorState` also accepts an optional node type union as a generic. Here, this would **add** the specified node types to the default ones. Example: `DefaultTypedEditorState`. + +This is a type-safe representation of the editor state. Looking at the auto-suggestions of `type` it will show you all the possible node types you can use. + +Make sure to only use types exported from `@payloadcms/richtext-lexical`, not from the lexical core packages. We only have control over types we export and can guarantee that those are correct, even though lexical core may export types with identical names. + +### Automatic type generation + +Lexical does not generate the accurate type definitions for your richText fields for you yet - this will be improved in the future. Currently, it only outputs the rough shape of the editor JSON which you can enhance using type assertions. From 78d01893b127f82dd4eb9ebee3cd686db83409ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:24:46 -0300 Subject: [PATCH 3/4] move slate to rich-text, and migration --- docs/rich-text/lexical.mdx | 9 --------- docs/{lexical => rich-text}/migration.mdx | 2 +- docs/rich-text/overview.mdx | 10 +++++++++- docs/rich-text/slate.mdx | 6 +++--- 4 files changed, 13 insertions(+), 14 deletions(-) delete mode 100644 docs/rich-text/lexical.mdx rename docs/{lexical => rich-text}/migration.mdx (99%) diff --git a/docs/rich-text/lexical.mdx b/docs/rich-text/lexical.mdx deleted file mode 100644 index bee27bd4928..00000000000 --- a/docs/rich-text/lexical.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Lexical Rich Text -label: Lexical -order: 30 -desc: Built by Meta, Lexical is an incredibly powerful rich text editor, and it works beautifully within Payload. -keywords: lexical, rich text, editor, headless cms ---- - -The new lexical docs can be found at [Lexical](/docs/lexical/overview). diff --git a/docs/lexical/migration.mdx b/docs/rich-text/migration.mdx similarity index 99% rename from docs/lexical/migration.mdx rename to docs/rich-text/migration.mdx index dbb8dbe966e..5c327f3d3e8 100644 --- a/docs/lexical/migration.mdx +++ b/docs/rich-text/migration.mdx @@ -1,7 +1,7 @@ --- title: Lexical Migration label: Migration -order: 30 +order: 90 desc: Migration from slate and payload-plugin-lexical to lexical keywords: lexical, rich text, editor, headless cms, migrate, migration --- diff --git a/docs/rich-text/overview.mdx b/docs/rich-text/overview.mdx index 464ffa4628c..3d36168f0f0 100644 --- a/docs/rich-text/overview.mdx +++ b/docs/rich-text/overview.mdx @@ -1,11 +1,19 @@ --- -title: Rich Text Editor Overview +title: Rich Text Editor label: Overview order: 10 desc: The Payload editor, based on Lexical, allows for great customization with unparalleled ease. keywords: lexical, rich text, editor, headless cms --- + + + The Payload editor is based on Lexical, Meta's rich text editor. The previous default editor was + based on Slate and is still supported. You can read [its documentation](/docs/rich-text/slate), + or the optional [migration guide](/docs/rich-text/migration) to migrate from Slate to Lexical. + + + One of Payload's goals is to build the best rich text editor experience that we possibly can. We want to combine the beauty and polish of the Medium editing experience with the strength and features of the Notion editor - all in one place. Classically, we've used SlateJS to work toward this goal, but building custom elements into Slate has proven to be more difficult than we'd like, and we've been keeping our options open. diff --git a/docs/rich-text/slate.mdx b/docs/rich-text/slate.mdx index 2d43322be06..aa412e21767 100644 --- a/docs/rich-text/slate.mdx +++ b/docs/rich-text/slate.mdx @@ -1,7 +1,7 @@ --- -title: Slate Rich Text -label: Slate -order: 20 +title: Slate Editor +label: Slate (legacy) +order: 100 desc: The Slate editor has been supported by Payload since beta. It's very powerful and stores content as JSON, which unlocks a ton of power. keywords: slatejs, slate, rich text, editor, headless cms --- From ab9cbaf9854045290d418827053d9429e929fd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:42:45 -0300 Subject: [PATCH 4/4] move rest of lexical files to richtext, fix fields/rich-text --- docs/fields/rich-text.mdx | 30 +++++++------------ .../building-custom-features.mdx | 0 docs/{lexical => rich-text}/converters.mdx | 0 docs/rich-text/overview.mdx | 2 +- 4 files changed, 11 insertions(+), 21 deletions(-) rename docs/{lexical => rich-text}/building-custom-features.mdx (100%) rename docs/{lexical => rich-text}/converters.mdx (100%) diff --git a/docs/fields/rich-text.mdx b/docs/fields/rich-text.mdx index cd5f0621447..5ea9425cc2d 100644 --- a/docs/fields/rich-text.mdx +++ b/docs/fields/rich-text.mdx @@ -6,7 +6,13 @@ desc: The Rich Text field allows dynamic content to be written through the Admin keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- -The Rich Text Field is a powerful way to allow editors to write dynamic content. The content is saved as JSON in the database and can be converted into any format, including HTML, that you need. +The Rich Text Field lets editors write and format dynamic content in a familiar interface. +The content is saved as JSON in the database and can be converted to HTML or any other format needed. + +Consistent with Payload's goal of making you learn as little of Payload as possible, customizing +and using the Rich Text Editor does not involve learning how to develop for a Payload rich text editor. +Instead, you can invest your time and effort into learning the underlying open-source tools that will allow +you to apply your learnings elsewhere as well. -Payload's rich text field is built on an "adapter pattern" which lets you specify which rich text editor you'd like to use. - -Right now, Payload is officially supporting two rich text editors: - -1. [SlateJS](/docs/rich-text/slate) - legacy, backwards-compatible with 1.0 -2. [Lexical](/docs/lexical/overview) - recommended - - - - Consistent with Payload's goal of making you learn as little of Payload as possible, customizing - and using the Rich Text Editor does not involve learning how to develop for a{' '}Payload{' '}rich text editor. - - - Instead, you can invest your time and effort into learning the underlying open-source tools that - will allow you to apply your learnings elsewhere as well. - - ## Config Options | Option | Description | @@ -47,7 +36,7 @@ Right now, Payload is officially supporting two rich text editors: | **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. | | **`required`** | Require this field to have a value. | | **`admin`** | Admin-specific configuration. [More details](#admin-options). | -| **`editor`** | Override the rich text editor specified in your base configuration for this field. | +| **`editor`** | Customize or override the rich text editor. [More details](/docs/rich-text/overview). | | **`custom`** | Extension point for adding custom data (e.g. for plugins) | | **`typescriptSchema`** | Override field type generation with providing a JSON schema | | **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) | @@ -79,4 +68,5 @@ The Rich Text Field inherits all of the default options from the base [Field Adm ## Editor-specific Options -For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/lexical/overview) depending on which editor you're using. +For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, +take a look at the [rich text editor documentation](/docs/rich-text/overview). diff --git a/docs/lexical/building-custom-features.mdx b/docs/rich-text/building-custom-features.mdx similarity index 100% rename from docs/lexical/building-custom-features.mdx rename to docs/rich-text/building-custom-features.mdx diff --git a/docs/lexical/converters.mdx b/docs/rich-text/converters.mdx similarity index 100% rename from docs/lexical/converters.mdx rename to docs/rich-text/converters.mdx diff --git a/docs/rich-text/overview.mdx b/docs/rich-text/overview.mdx index 3d36168f0f0..d3cfc31f369 100644 --- a/docs/rich-text/overview.mdx +++ b/docs/rich-text/overview.mdx @@ -10,7 +10,7 @@ keywords: lexical, rich text, editor, headless cms The Payload editor is based on Lexical, Meta's rich text editor. The previous default editor was based on Slate and is still supported. You can read [its documentation](/docs/rich-text/slate), - or the optional [migration guide](/docs/rich-text/migration) to migrate from Slate to Lexical. + or the optional [migration guide](/docs/rich-text/migration) to migrate from Slate to Lexical (recommended).