-
Notifications
You must be signed in to change notification settings - Fork 3.1k
feat(richtext-lexical): client-side block markdown shortcuts, code block #13813
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 74 commits
4274182
7924bc6
4f86ea4
af7c265
e173d2c
aad7d25
a4c5f81
266049e
4a09cf6
788c8fb
8c1ccac
2281bf7
1801169
446655c
6cf1394
5c9b439
d4b5fd4
e196190
da2e6a5
487cfcb
9049a7d
0a319ae
732d9eb
f5d32fd
cc9d111
1b221b9
a5edf7e
3355a4e
e91df8c
44f46b5
d68b36a
3ef9843
e555b62
961969d
9d3fc43
7b8d217
128345e
56a1b3b
df886cf
898dbd3
d8b427e
df4793d
062046e
58ab390
5d79493
cb85185
deb0686
917c03d
7a8ba17
152bf35
5ab25cf
6b23c29
b804ca6
3d25465
148afe0
7dedb09
ff6711a
b78b95f
88ce4e9
e8ce261
15aa3c7
c83e331
9600e0a
e981770
2be3080
4d6e3fe
0da0ef2
93a850c
01ef157
c8a5586
86a4276
efcc3d1
246b612
c8403a3
11d4c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -418,6 +418,69 @@ BlocksFeature({ | |
| }) | ||
| ``` | ||
|
|
||
| #### Code Blocks | ||
|
|
||
| Payload exports a premade CodeBlock that you can import and use in your project. It supports syntax highlighting, dynamically selecting the language and loading in external type definitions: | ||
|
|
||
| ```ts | ||
| import { BlocksFeature, CodeBlock } from '@payloadcms/richtext-lexical' | ||
|
|
||
| // ... | ||
| BlocksFeature({ | ||
| blocks: [ | ||
| CodeBlock({ | ||
| defaultLanguage: 'ts', | ||
| languages: { | ||
| js: 'JavaScript', | ||
| plaintext: 'Plain Text', | ||
| ts: 'TypeScript', | ||
| }, | ||
| }), | ||
| ], | ||
| }), | ||
| // ... | ||
| ``` | ||
|
|
||
| When using TypeScript, you can also pass in additional type definitions that will be available in the editor. Here's an example of how to make `payload` and `react` available in the editor: | ||
|
|
||
| ```ts | ||
| import { BlocksFeature, CodeBlock } from '@payloadcms/richtext-lexical' | ||
|
|
||
| // ... | ||
| BlocksFeature({ | ||
| blocks: [ | ||
| CodeBlock({ | ||
| slug: 'PayloadCode', | ||
| languages: { | ||
| ts: 'TypeScript', | ||
| }, | ||
| typescript: { | ||
| fetchTypes: [ | ||
| { | ||
| // The index.bundled.d.ts contains all the types for Payload in one file, so that Monaco doesn't need to fetch multiple files. | ||
| // This file may be removed in the future and is not guaranteed to be available in future versions of Payload. | ||
| url: 'https://unpkg.com/[email protected]/dist/index.bundled.d.ts', | ||
| filePath: 'file:///node_modules/payload/index.d.ts', | ||
| }, | ||
| { | ||
| url: 'https://unpkg.com/@types/[email protected]/index.d.ts', | ||
| filePath: 'file:///node_modules/@types/react/index.d.ts', | ||
| }, | ||
| ], | ||
| paths: { | ||
| payload: ['file:///node_modules/payload/index.d.ts'], | ||
| react: ['file:///node_modules/@types/react/index.d.ts'], | ||
| }, | ||
| typeRoots: ['node_modules/@types', 'node_modules/payload'], | ||
| // Enable type checking. By default, only syntax checking is enabled. | ||
| enableSemanticValidation: true, | ||
| }, | ||
| }), | ||
| ], | ||
| }), | ||
| // ... | ||
| ``` | ||
|
|
||
| ### TreeViewFeature | ||
|
|
||
| - Description: Provides a debug panel below the editor showing the editor's internal state, DOM tree, and time travel debugging. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1061,6 +1061,7 @@ export type CodeField = { | |
| Label?: CustomComponent<CodeFieldLabelClientComponent | CodeFieldLabelServerComponent> | ||
| } & Admin['components'] | ||
| editorOptions?: EditorProps['options'] | ||
| editorProps?: Partial<EditorProps> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Monaco + some extra properties.
You're right! The previous type was inaccurate because the height property was effectively ignored. I fixed this by moving our height property override up, before we spread the props - the type should be accurate now! Few benefits over just excluding the property:
|
||
| language?: string | ||
| } & Admin | ||
| maxLength?: number | ||
|
|
@@ -1070,8 +1071,9 @@ export type CodeField = { | |
| } & Omit<FieldBase, 'admin' | 'validate'> | ||
|
|
||
| export type CodeFieldClient = { | ||
| // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve | ||
| admin?: AdminClient & Pick<CodeField['admin'], 'editorOptions' | 'language'> | ||
| admin?: AdminClient & | ||
| // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve | ||
| Partial<Pick<CodeField['admin'], 'editorOptions' | 'editorProps' | 'language'>> | ||
| } & Omit<FieldBaseClient, 'admin'> & | ||
| Pick<CodeField, 'maxLength' | 'minLength' | 'type'> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,11 @@ | ||
| 'use client' | ||
| import React from 'react' | ||
|
|
||
| import { useBlockComponentContext } from '../BlockContent.js' | ||
| import { type BlockCollapsibleProps, useBlockComponentContext } from '../BlockContent.js' | ||
|
|
||
| export const BlockCollapsible: React.FC<{ | ||
| children?: React.ReactNode | ||
| editButton?: boolean | ||
|
|
||
| /** | ||
| * Override the default label with a custom label | ||
| */ | ||
| Label?: React.ReactNode | ||
| removeButton?: boolean | ||
| }> = ({ children, editButton, Label, removeButton }) => { | ||
| export const BlockCollapsible: React.FC<BlockCollapsibleProps> = (props) => { | ||
| const { children, ...rest } = props | ||
| const { BlockCollapsible } = useBlockComponentContext() | ||
|
|
||
| return BlockCollapsible ? ( | ||
| <BlockCollapsible editButton={editButton} Label={Label} removeButton={removeButton}> | ||
| {children} | ||
| </BlockCollapsible> | ||
| ) : null | ||
| return BlockCollapsible ? <BlockCollapsible {...rest}>{children}</BlockCollapsible> : null | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why define supported languages when they could all be included?
I thought it might be a bundle thing or something, but they already come with Monaco for the same price, right?
In case it's a matter of making the dropdown menu not so long, I would simply do it with limited height + scroll and search (Combobox)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
Screenshot.2025-10-06.at.20.01.07.mp4