From a9c76d9f02469c66fe5fc9d2fd65b1f7578c930b Mon Sep 17 00:00:00 2001 From: Chris Arter Date: Fri, 8 May 2026 11:41:38 -0400 Subject: [PATCH] feat(blocks): register custom blocks on body fields --- src/collections/Pages.ts | 4 +-- src/collections/Posts.ts | 4 +-- src/collections/Projects.ts | 4 +-- src/lib/lexical-editor.ts | 16 ++++++++++++ src/payload-types.ts | 51 +++++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 src/lib/lexical-editor.ts diff --git a/src/collections/Pages.ts b/src/collections/Pages.ts index 052b4b1..5b96e5b 100644 --- a/src/collections/Pages.ts +++ b/src/collections/Pages.ts @@ -1,5 +1,5 @@ import type { CollectionConfig } from 'payload' -import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { bodyEditor } from '@/lib/lexical-editor' export const Pages: CollectionConfig = { slug: 'pages', @@ -28,6 +28,6 @@ export const Pages: CollectionConfig = { { name: 'image', type: 'upload', relationTo: 'media' }, ], }, - { name: 'body', type: 'richText', editor: lexicalEditor() }, + { name: 'body', type: 'richText', editor: bodyEditor }, ], } diff --git a/src/collections/Posts.ts b/src/collections/Posts.ts index 458e567..964c9b6 100644 --- a/src/collections/Posts.ts +++ b/src/collections/Posts.ts @@ -1,5 +1,5 @@ import type { CollectionConfig } from 'payload' -import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { bodyEditor } from '@/lib/lexical-editor' export const Posts: CollectionConfig = { slug: 'posts', @@ -42,7 +42,7 @@ export const Posts: CollectionConfig = { { name: 'image', type: 'upload', relationTo: 'media' }, ], }, - { name: 'body', type: 'richText', editor: lexicalEditor() }, + { name: 'body', type: 'richText', editor: bodyEditor }, ], indexes: [ { fields: ['publishDate', '_status'] }, diff --git a/src/collections/Projects.ts b/src/collections/Projects.ts index d823834..4dc5cdc 100644 --- a/src/collections/Projects.ts +++ b/src/collections/Projects.ts @@ -1,5 +1,5 @@ import type { CollectionConfig } from 'payload' -import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { bodyEditor } from '@/lib/lexical-editor' export const Projects: CollectionConfig = { slug: 'projects', @@ -30,6 +30,6 @@ export const Projects: CollectionConfig = { { name: 'image', type: 'upload', relationTo: 'media' }, ], }, - { name: 'body', type: 'richText', editor: lexicalEditor() }, + { name: 'body', type: 'richText', editor: bodyEditor }, ], } diff --git a/src/lib/lexical-editor.ts b/src/lib/lexical-editor.ts new file mode 100644 index 0000000..778b24a --- /dev/null +++ b/src/lib/lexical-editor.ts @@ -0,0 +1,16 @@ +import { + BlocksFeature, + HeadingFeature, + HorizontalRuleFeature, + lexicalEditor, +} from '@payloadcms/richtext-lexical' +import { LinkPreviewBlock, CalloutBlock, MediaBlock } from '@/blocks' + +export const bodyEditor = lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ enabledHeadingSizes: ['h2', 'h3', 'h4', 'h5', 'h6'] }), + HorizontalRuleFeature(), + BlocksFeature({ blocks: [LinkPreviewBlock, CalloutBlock, MediaBlock] }), + ], +}) diff --git a/src/payload-types.ts b/src/payload-types.ts index 5107fdf..1113746 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -556,6 +556,57 @@ export interface CollectionsWidget { }; width: 'full'; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "LinkPreviewBlock". + */ +export interface LinkPreviewBlock { + url: string; + title?: string | null; + description?: string | null; + image?: (number | null) | Media; + id?: string | null; + blockName?: string | null; + blockType: 'linkPreview'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "CalloutBlock". + */ +export interface CalloutBlock { + title?: string | null; + variant?: ('default' | 'note' | 'warning' | 'tip') | null; + content?: { + root: { + type: string; + children: { + type: any; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + id?: string | null; + blockName?: string | null; + blockType: 'callout'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "MediaBlock". + */ +export interface MediaBlock { + media: number | Media; + caption?: string | null; + widthHint?: ('full' | 'wide' | 'inline') | null; + id?: string | null; + blockName?: string | null; + blockType: 'mediaBlock'; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". -- 2.51.2