Skip to content

Commit d66b348

Browse files
authored
feat(richtext-lexical)!: simplify creation of features (#6885)
**BREAKING:** - ServerFeature: `ClientComponent` has been renamed to `ClientFeature` - ServerFeature: The nested `serverFeatureProps` has been renamed to `sanitizedServerFeatureProps` - ServerFeature: The FeatureProviderProviderServer type now expects 3 generics instead of 2. We have split the props generic into sanitized & unsanitized props - ClientFeature: The FeatureProviderProviderClient type now expects 2 generics instead of 1. We have split the props generic into sanitized & unsanitized props - ClientFeature: The nested `clientFeatureProps` has been renamed to `sanitizedClientFeatureProps`
1 parent ead7d95 commit d66b348

File tree

92 files changed

+1588
-1795
lines changed

Some content is hidden

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

92 files changed

+1588
-1795
lines changed

packages/richtext-lexical/src/cell/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ export const RichTextCell: React.FC<
3434
const clientFunctions = useClientFunctions()
3535
const [hasLoadedFeatures, setHasLoadedFeatures] = useState(false)
3636

37-
const [featureProviders, setFeatureProviders] = useState<FeatureProviderClient<unknown>[]>([])
37+
const [featureProviders, setFeatureProviders] = useState<
38+
FeatureProviderClient<unknown, unknown>[]
39+
>([])
3840

3941
const [finalSanitizedEditorConfig, setFinalSanitizedEditorConfig] =
4042
useState<SanitizedClientEditorConfig>(null)
@@ -55,7 +57,7 @@ export const RichTextCell: React.FC<
5557

5658
useEffect(() => {
5759
if (!hasLoadedFeatures) {
58-
const featureProvidersLocal: FeatureProviderClient<unknown>[] = []
60+
const featureProvidersLocal: FeatureProviderClient<unknown, unknown>[] = []
5961
let featureProvidersAndComponentsLoaded = 0 // feature providers and components only
6062

6163
Object.entries(clientFunctions).forEach(([key, plugin]) => {
@@ -179,7 +181,7 @@ export const RichTextCell: React.FC<
179181
return FeatureComponent
180182
})
181183
: null}
182-
{featureProvider.ClientComponent}
184+
{featureProvider.ClientFeature}
183185
</React.Fragment>
184186
)
185187
})}

packages/richtext-lexical/src/exports/client/index.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,32 @@
22
'use client'
33

44
export { RichTextCell } from '../../cell/index.js'
5-
export { AlignFeatureClientComponent } from '../../features/align/feature.client.js'
6-
export { BlockquoteFeatureClientComponent } from '../../features/blockquote/feature.client.js'
7-
export { BlocksFeatureClientComponent } from '../../features/blocks/feature.client.js'
5+
export { AlignFeatureClient } from '../../features/align/feature.client.js'
6+
export { BlockquoteFeatureClient } from '../../features/blockquote/feature.client.js'
7+
export { BlocksFeatureClient } from '../../features/blocks/feature.client.js'
88
export { createClientComponent } from '../../features/createClientComponent.js'
9-
export { TestRecorderFeatureClientComponent } from '../../features/debug/testRecorder/feature.client.js'
10-
export { TreeViewFeatureClientComponent } from '../../features/debug/treeView/feature.client.js'
11-
export { BoldFeatureClientComponent } from '../../features/format/bold/feature.client.js'
12-
export { InlineCodeFeatureClientComponent } from '../../features/format/inlineCode/feature.client.js'
13-
export { ItalicFeatureClientComponent } from '../../features/format/italic/feature.client.js'
9+
export { TestRecorderFeatureClient } from '../../features/debug/testRecorder/feature.client.js'
10+
export { TreeViewFeatureClient } from '../../features/debug/treeView/feature.client.js'
11+
export { BoldFeatureClient } from '../../features/format/bold/feature.client.js'
12+
export { InlineCodeFeatureClient } from '../../features/format/inlineCode/feature.client.js'
13+
export { ItalicFeatureClient } from '../../features/format/italic/feature.client.js'
1414
export { toolbarFormatGroupWithItems } from '../../features/format/shared/toolbarFormatGroup.js'
15-
export { StrikethroughFeatureClientComponent } from '../../features/format/strikethrough/feature.client.js'
16-
export { SubscriptFeatureClientComponent } from '../../features/format/subscript/feature.client.js'
17-
export { SuperscriptFeatureClientComponent } from '../../features/format/superscript/feature.client.js'
18-
export { UnderlineFeatureClientComponent } from '../../features/format/underline/feature.client.js'
19-
export { HeadingFeatureClientComponent } from '../../features/heading/feature.client.js'
20-
export { HorizontalRuleFeatureClientComponent } from '../../features/horizontalRule/feature.client.js'
21-
export { IndentFeatureClientComponent } from '../../features/indent/feature.client.js'
22-
export { LinkFeatureClientComponent } from '../../features/link/feature.client.js'
23-
export { ChecklistFeatureClientComponent } from '../../features/lists/checklist/feature.client.js'
24-
export { OrderedListFeatureClientComponent } from '../../features/lists/orderedList/feature.client.js'
25-
export { UnorderedListFeatureClientComponent } from '../../features/lists/unorderedList/feature.client.js'
26-
export { LexicalPluginToLexicalFeatureClientComponent } from '../../features/migrations/lexicalPluginToLexical/feature.client.js'
27-
export { SlateToLexicalFeatureClientComponent } from '../../features/migrations/slateToLexical/feature.client.js'
28-
export { ParagraphFeatureClientComponent } from '../../features/paragraph/feature.client.js'
15+
export { StrikethroughFeatureClient } from '../../features/format/strikethrough/feature.client.js'
16+
export { SubscriptFeatureClient } from '../../features/format/subscript/feature.client.js'
17+
export { SuperscriptFeatureClient } from '../../features/format/superscript/feature.client.js'
18+
export { UnderlineFeatureClient } from '../../features/format/underline/feature.client.js'
19+
export { HeadingFeatureClient } from '../../features/heading/feature.client.js'
20+
export { HorizontalRuleFeatureClient } from '../../features/horizontalRule/feature.client.js'
21+
export { IndentFeatureClient } from '../../features/indent/feature.client.js'
22+
export { LinkFeatureClient } from '../../features/link/feature.client.js'
23+
export { ChecklistFeatureClient } from '../../features/lists/checklist/feature.client.js'
24+
export { OrderedListFeatureClient } from '../../features/lists/orderedList/feature.client.js'
25+
export { UnorderedListFeatureClient } from '../../features/lists/unorderedList/feature.client.js'
26+
export { LexicalPluginToLexicalFeatureClient } from '../../features/migrations/lexicalPluginToLexical/feature.client.js'
27+
export { SlateToLexicalFeatureClient } from '../../features/migrations/slateToLexical/feature.client.js'
28+
export { ParagraphFeatureClient } from '../../features/paragraph/feature.client.js'
2929

30-
export { RelationshipFeatureClientComponent } from '../../features/relationship/feature.client.js'
30+
export { RelationshipFeatureClient } from '../../features/relationship/feature.client.js'
3131

3232
export { toolbarAddDropdownGroupWithItems } from '../../features/shared/toolbar/addDropdownGroup.js'
3333
export { toolbarFeatureButtonsGroupWithItems } from '../../features/shared/toolbar/featureButtonsGroup.js'

packages/richtext-lexical/src/features/align/feature.client.tsx

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
import { $isElementNode, $isRangeSelection, FORMAT_ELEMENT_COMMAND } from 'lexical'
44

55
import type { ToolbarGroup } from '../toolbars/types.js'
6-
import type { FeatureProviderProviderClient } from '../types.js'
76

87
import { AlignCenterIcon } from '../../lexical/ui/icons/AlignCenter/index.js'
98
import { AlignJustifyIcon } from '../../lexical/ui/icons/AlignJustify/index.js'
109
import { AlignLeftIcon } from '../../lexical/ui/icons/AlignLeft/index.js'
1110
import { AlignRightIcon } from '../../lexical/ui/icons/AlignRight/index.js'
12-
import { createClientComponent } from '../createClientComponent.js'
11+
import { createClientFeature } from '../../utilities/createClientFeature.js'
1312
import { toolbarAlignGroupWithItems } from './toolbarAlignGroup.js'
1413

1514
const toolbarGroups: ToolbarGroup[] = [
@@ -149,19 +148,11 @@ const toolbarGroups: ToolbarGroup[] = [
149148
]),
150149
]
151150

152-
const AlignFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {
153-
return {
154-
clientFeatureProps: props,
155-
feature: () => ({
156-
clientFeatureProps: props,
157-
toolbarFixed: {
158-
groups: toolbarGroups,
159-
},
160-
toolbarInline: {
161-
groups: toolbarGroups,
162-
},
163-
}),
164-
}
165-
}
166-
167-
export const AlignFeatureClientComponent = createClientComponent(AlignFeatureClient)
151+
export const AlignFeatureClient = createClientFeature({
152+
toolbarFixed: {
153+
groups: toolbarGroups,
154+
},
155+
toolbarInline: {
156+
groups: toolbarGroups,
157+
},
158+
})
Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
1-
import type { FeatureProviderProviderServer } from '../types.js'
2-
31
// eslint-disable-next-line payload/no-imports-from-exports-dir
4-
import { AlignFeatureClientComponent } from '../../exports/client/index.js'
2+
import { AlignFeatureClient } from '../../exports/client/index.js'
3+
import { createServerFeature } from '../../utilities/createServerFeature.js'
54
import { i18n } from './i18n.js'
65

7-
export const AlignFeature: FeatureProviderProviderServer<undefined, undefined> = (props) => {
8-
return {
9-
feature: () => {
10-
return {
11-
ClientComponent: AlignFeatureClientComponent,
12-
clientFeatureProps: null,
13-
i18n,
14-
serverFeatureProps: props,
15-
}
16-
},
17-
key: 'align',
18-
serverFeatureProps: props,
19-
}
20-
}
6+
export const AlignFeature = createServerFeature({
7+
feature: {
8+
ClientFeature: AlignFeatureClient,
9+
i18n,
10+
},
11+
key: 'align',
12+
})

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

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ import { $setBlocksType } from '@lexical/selection'
55
import { $getSelection, $isRangeSelection } from 'lexical'
66

77
import type { ToolbarGroup } from '../toolbars/types.js'
8-
import type { FeatureProviderProviderClient } from '../types.js'
98

109
import { BlockquoteIcon } from '../../lexical/ui/icons/Blockquote/index.js'
11-
import { createClientComponent } from '../createClientComponent.js'
10+
import { createClientFeature } from '../../utilities/createClientFeature.js'
1211
import { slashMenuBasicGroupWithItems } from '../shared/slashMenu/basicGroup.js'
1312
import { toolbarTextDropdownGroupWithItems } from '../shared/toolbar/textDropdownGroup.js'
1413
import { MarkdownTransformer } from './markdownTransformer.js'
@@ -43,42 +42,34 @@ const toolbarGroups: ToolbarGroup[] = [
4342
]),
4443
]
4544

46-
const BlockquoteFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {
47-
return {
48-
clientFeatureProps: props,
49-
feature: () => ({
50-
clientFeatureProps: props,
51-
markdownTransformers: [MarkdownTransformer],
52-
nodes: [QuoteNode],
45+
export const BlockquoteFeatureClient = createClientFeature({
46+
markdownTransformers: [MarkdownTransformer],
47+
nodes: [QuoteNode],
5348

54-
slashMenu: {
55-
groups: [
56-
slashMenuBasicGroupWithItems([
57-
{
58-
Icon: BlockquoteIcon,
59-
key: 'blockquote',
60-
keywords: ['quote', 'blockquote'],
61-
label: ({ i18n }) => {
62-
return i18n.t('lexical:blockquote:label')
63-
},
64-
onSelect: ({ editor }) => {
65-
editor.update(() => {
66-
const selection = $getSelection()
67-
$setBlocksType(selection, () => $createQuoteNode())
68-
})
69-
},
70-
},
71-
]),
72-
],
73-
},
74-
toolbarFixed: {
75-
groups: toolbarGroups,
76-
},
77-
toolbarInline: {
78-
groups: toolbarGroups,
79-
},
80-
}),
81-
}
82-
}
83-
84-
export const BlockquoteFeatureClientComponent = createClientComponent(BlockquoteFeatureClient)
49+
slashMenu: {
50+
groups: [
51+
slashMenuBasicGroupWithItems([
52+
{
53+
Icon: BlockquoteIcon,
54+
key: 'blockquote',
55+
keywords: ['quote', 'blockquote'],
56+
label: ({ i18n }) => {
57+
return i18n.t('lexical:blockquote:label')
58+
},
59+
onSelect: ({ editor }) => {
60+
editor.update(() => {
61+
const selection = $getSelection()
62+
$setBlocksType(selection, () => $createQuoteNode())
63+
})
64+
},
65+
},
66+
]),
67+
],
68+
},
69+
toolbarFixed: {
70+
groups: toolbarGroups,
71+
},
72+
toolbarInline: {
73+
groups: toolbarGroups,
74+
},
75+
})
Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,42 @@
11
import { QuoteNode } from '@lexical/rich-text'
22

3-
import type { FeatureProviderProviderServer } from '../types.js'
4-
53
// eslint-disable-next-line payload/no-imports-from-exports-dir
6-
import { BlockquoteFeatureClientComponent } from '../../exports/client/index.js'
4+
import { BlockquoteFeatureClient } from '../../exports/client/index.js'
5+
import { createServerFeature } from '../../utilities/createServerFeature.js'
76
import { convertLexicalNodesToHTML } from '../converters/html/converter/index.js'
87
import { createNode } from '../typeUtilities.js'
98
import { i18n } from './i18n.js'
109
import { MarkdownTransformer } from './markdownTransformer.js'
1110

12-
export const BlockquoteFeature: FeatureProviderProviderServer<undefined, undefined> = (props) => {
13-
return {
14-
feature: () => {
15-
return {
16-
ClientComponent: BlockquoteFeatureClientComponent,
17-
clientFeatureProps: null,
18-
i18n,
19-
markdownTransformers: [MarkdownTransformer],
20-
nodes: [
21-
createNode({
22-
converters: {
23-
html: {
24-
converter: async ({ converters, node, parent, req }) => {
25-
const childrenText = await convertLexicalNodesToHTML({
26-
converters,
27-
lexicalNodes: node.children,
28-
parent: {
29-
...node,
30-
parent,
31-
},
32-
req,
33-
})
34-
35-
return `<blockquote>${childrenText}</blockquote>`
11+
export const BlockquoteFeature = createServerFeature({
12+
feature: {
13+
ClientFeature: BlockquoteFeatureClient,
14+
clientFeatureProps: null,
15+
i18n,
16+
markdownTransformers: [MarkdownTransformer],
17+
nodes: [
18+
createNode({
19+
converters: {
20+
html: {
21+
converter: async ({ converters, node, parent, req }) => {
22+
const childrenText = await convertLexicalNodesToHTML({
23+
converters,
24+
lexicalNodes: node.children,
25+
parent: {
26+
...node,
27+
parent,
3628
},
37-
nodeTypes: [QuoteNode.getType()],
38-
},
29+
req,
30+
})
31+
32+
return `<blockquote>${childrenText}</blockquote>`
3933
},
40-
node: QuoteNode,
41-
}),
42-
],
43-
serverFeatureProps: props,
44-
}
45-
},
46-
key: 'blockquote',
47-
serverFeatureProps: props,
48-
}
49-
}
34+
nodeTypes: [QuoteNode.getType()],
35+
},
36+
},
37+
node: QuoteNode,
38+
}),
39+
],
40+
},
41+
key: 'blockquote',
42+
})

packages/richtext-lexical/src/features/blocks/component/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const BlockComponent: React.FC<Props> = (props) => {
6161

6262
const reducedBlock: ReducedBlock = (
6363
editorConfig?.resolvedFeatureMap?.get('blocks')
64-
?.clientFeatureProps as ClientComponentProps<BlocksFeatureClientProps>
64+
?.sanitizedClientFeatureProps as ClientComponentProps<BlocksFeatureClientProps>
6565
)?.reducedBlocks?.find((block) => block.slug === formData?.blockType)
6666

6767
const fieldMap = richTextComponentMap.get(componentMapRenderedFieldsPath)

packages/richtext-lexical/src/features/blocks/drawer/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const BlocksDrawerComponent: React.FC = () => {
8787

8888
const reducedBlocks = (
8989
editorConfig?.resolvedFeatureMap?.get('blocks')
90-
?.clientFeatureProps as ClientComponentProps<BlocksFeatureClientProps>
90+
?.sanitizedClientFeatureProps as ClientComponentProps<BlocksFeatureClientProps>
9191
)?.reducedBlocks
9292

9393
useEffect(() => {

0 commit comments

Comments
 (0)