Skip to content

Commit 8e55a2a

Browse files
authored
feat(richtext-lexical)!: strongly typed PluginComponent types, remove LexicalBlocks, improve exports, fix e2e (#6255)
**BREAKING:** - Narrows the type of the `plugins` prop of lexical features. Client props are now also automatically provided to the plugin components. To migrate, type your plugin as either `PluginComponent` or PluginComponentWithAnchor. - `BlockQuoteFeature` has been renamed to `BlockquoteFeature` - `createClientComponent` is now exported only from /components - The `LexicalBlocks` and `FieldWithRichTextRequiredEditor` types have been removed in favor of just `Blocks` & `Fields`, as well as improved validation.
1 parent 0f306da commit 8e55a2a

File tree

49 files changed

+232
-170
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+232
-170
lines changed

packages/payload/src/admin/RichText.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,15 @@ export type RichTextAdapterProvider<
9292
ExtraFieldProperties = {},
9393
> = ({
9494
config,
95+
isRoot,
9596
}: {
9697
config: SanitizedConfig
98+
/**
99+
* Whether or not this is the root richText editor, defined in the payload.config.ts.
100+
*
101+
* @default false
102+
*/
103+
isRoot?: boolean
97104
}) =>
98105
| Promise<RichTextAdapter<Value, AdapterProps, ExtraFieldProperties>>
99106
| RichTextAdapter<Value, AdapterProps, ExtraFieldProperties>

packages/payload/src/config/sanitize.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ export const sanitizeConfig = async (incomingConfig: Config): Promise<SanitizedC
150150
if (typeof incomingConfig.editor === 'function') {
151151
config.editor = await incomingConfig.editor({
152152
config: config as SanitizedConfig,
153+
isRoot: true,
153154
})
154155
}
155156

packages/payload/src/errors/MissingEditorProp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { APIError } from './APIError.js'
66
export class MissingEditorProp extends APIError {
77
constructor(field: Field) {
88
super(
9-
`RichText field${fieldAffectsData(field) ? ` "${field.name}"` : ''} is missing the editor prop`,
9+
`RichText field${fieldAffectsData(field) ? ` "${field.name}"` : ''} is missing the editor prop. For sub-richText fields, the editor props is required, as it would otherwise create infinite recursion.`,
1010
)
1111
}
1212
}

packages/payload/src/exports/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ export type {
7272
FieldWithMany,
7373
FieldWithMaxDepth,
7474
FieldWithPath,
75-
FieldWithRichTextRequiredEditor,
7675
FieldWithSubFields,
7776
FilterOptions,
7877
FilterOptionsProps,
@@ -91,7 +90,6 @@ export type {
9190
RelationshipField,
9291
RelationshipValue,
9392
RichTextField,
94-
RichTextFieldRequiredEditor,
9593
RowAdmin,
9694
RowField,
9795
SelectField,

packages/payload/src/fields/config/sanitize.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ export const sanitizeFields = async ({
161161
}
162162

163163
if (typeof field.editor === 'function') {
164-
field.editor = await field.editor({ config: _config })
164+
field.editor = await field.editor({
165+
config: _config,
166+
isRoot: requireFieldLevelRichTextEditor,
167+
})
165168
}
166169

167170
// Add editor adapter hooks to field hooks

packages/payload/src/fields/config/types.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -607,16 +607,6 @@ export type RichTextField<
607607
type: 'richText'
608608
} & ExtraProperties
609609

610-
export type RichTextFieldRequiredEditor<
611-
Value extends object = any,
612-
AdapterProps = any,
613-
ExtraProperties = object,
614-
> = Omit<RichTextField<Value, AdapterProps, ExtraProperties>, 'editor'> & {
615-
editor:
616-
| RichTextAdapter<Value, AdapterProps, AdapterProps>
617-
| RichTextAdapterProvider<Value, AdapterProps, AdapterProps>
618-
}
619-
620610
export type ArrayField = FieldBase & {
621611
admin?: Admin & {
622612
components?: {
@@ -730,10 +720,6 @@ export type Field =
730720
| UIField
731721
| UploadField
732722

733-
export type FieldWithRichTextRequiredEditor =
734-
| Exclude<Field, RichTextField>
735-
| RichTextFieldRequiredEditor
736-
737723
export type FieldAffectingData =
738724
| ArrayField
739725
| BlockField

packages/richtext-lexical/src/exports/components.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
export { RichTextCell } from '../cell/index.js'
2-
export { ToolbarButton } from '../field/features/toolbars/shared/ToolbarButton/index.js'
2+
export { createClientComponent } from '../field/features/createClientComponent.js'
33

4+
export { toolbarFormatGroupWithItems } from '../field/features/format/shared/toolbarFormatGroup.js'
5+
export { toolbarAddDropdownGroupWithItems } from '../field/features/shared/toolbar/addDropdownGroup.js'
6+
export { toolbarFeatureButtonsGroupWithItems } from '../field/features/shared/toolbar/featureButtonsGroup.js'
7+
export { toolbarTextDropdownGroupWithItems } from '../field/features/shared/toolbar/textDropdownGroup.js'
8+
export { ToolbarButton } from '../field/features/toolbars/shared/ToolbarButton/index.js'
49
export { ToolbarDropdown } from '../field/features/toolbars/shared/ToolbarDropdown/index.js'
10+
511
export { RichTextField } from '../field/index.js'
612
export {
713
type EditorFocusContextType,

packages/richtext-lexical/src/field/features/blockquote/feature.client.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const toolbarGroups: ToolbarGroup[] = [
4040
]),
4141
]
4242

43-
const BlockQuoteFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {
43+
const BlockquoteFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {
4444
return {
4545
clientFeatureProps: props,
4646
feature: () => ({
@@ -80,4 +80,4 @@ const BlockQuoteFeatureClient: FeatureProviderProviderClient<undefined> = (props
8080
}
8181
}
8282

83-
export const BlockQuoteFeatureClientComponent = createClientComponent(BlockQuoteFeatureClient)
83+
export const BlockquoteFeatureClientComponent = createClientComponent(BlockquoteFeatureClient)

packages/richtext-lexical/src/field/features/blockquote/feature.server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import type { FeatureProviderProviderServer } from '../types.js'
44

55
import { convertLexicalNodesToHTML } from '../converters/html/converter/index.js'
66
import { createNode } from '../typeUtilities.js'
7-
import { BlockQuoteFeatureClientComponent } from './feature.client.js'
7+
import { BlockquoteFeatureClientComponent } from './feature.client.js'
88
import { MarkdownTransformer } from './markdownTransformer.js'
99

10-
export const BlockQuoteFeature: FeatureProviderProviderServer<undefined, undefined> = (props) => {
10+
export const BlockquoteFeature: FeatureProviderProviderServer<undefined, undefined> = (props) => {
1111
return {
1212
feature: () => {
1313
return {
14-
ClientComponent: BlockQuoteFeatureClientComponent,
14+
ClientComponent: BlockquoteFeatureClientComponent,
1515
clientFeatureProps: null,
1616
markdownTransformers: [MarkdownTransformer],
1717
nodes: [

packages/richtext-lexical/src/field/features/blocks/feature.server.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Config } from 'payload/config'
2-
import type { Block, BlockField, Field, FieldWithRichTextRequiredEditor } from 'payload/types'
2+
import type { Block, BlockField, Field } from 'payload/types'
33

44
import { traverseFields } from '@payloadcms/next/utilities'
55
import { baseBlockFields, sanitizeFields } from 'payload/config'
@@ -14,33 +14,29 @@ import { BlockNode } from './nodes/BlocksNode.js'
1414
import { blockPopulationPromiseHOC } from './populationPromise.js'
1515
import { blockValidationHOC } from './validate.js'
1616

17-
export type LexicalBlock = Omit<Block, 'fields'> & {
18-
fields: FieldWithRichTextRequiredEditor[]
19-
}
20-
2117
export type BlocksFeatureProps = {
22-
blocks: LexicalBlock[]
18+
blocks: Block[]
2319
}
2420

2521
export const BlocksFeature: FeatureProviderProviderServer<
2622
BlocksFeatureProps,
2723
BlocksFeatureClientProps
2824
> = (props) => {
2925
return {
30-
feature: async ({ config: _config }) => {
26+
feature: async ({ config: _config, isRoot }) => {
3127
if (props?.blocks?.length) {
3228
const validRelationships = _config.collections.map((c) => c.slug) || []
3329

3430
for (const block of props.blocks) {
35-
block.fields = block.fields.concat(baseBlockFields as FieldWithRichTextRequiredEditor[])
31+
block.fields = block.fields.concat(baseBlockFields)
3632
block.labels = !block.labels ? formatLabels(block.slug) : block.labels
3733

38-
block.fields = (await sanitizeFields({
34+
block.fields = await sanitizeFields({
3935
config: _config as unknown as Config,
4036
fields: block.fields,
41-
requireFieldLevelRichTextEditor: true,
37+
requireFieldLevelRichTextEditor: isRoot,
4238
validRelationships,
43-
})) as FieldWithRichTextRequiredEditor[]
39+
})
4440
}
4541
}
4642

0 commit comments

Comments
 (0)