chore(richtext-lexical): updated lexical incoming config API

This commit is contained in:
Alessio Gravili
2023-10-07 00:22:13 +02:00
parent b6de427f04
commit acfda5d8d4
4 changed files with 109 additions and 83 deletions

View File

@@ -1,7 +1,9 @@
import type { EditorConfig as LexicalEditorConfig } from 'lexical/LexicalEditor'
import type { FeatureProvider } from '../../features/types'
import type { EditorConfig, SanitizedEditorConfig } from './types'
import { BlockQuoteFeature } from '../../features/BlockQuote'
import { BlocksFeature } from '../../features/Blocks'
import { HeadingFeature } from '../../features/Heading'
import { LinkFeature } from '../../features/Link'
import { ParagraphFeature } from '../../features/Paragraph'
@@ -22,32 +24,36 @@ import { UnoderedListFeature } from '../../features/lists/UnorderedList'
import { LexicalEditorTheme } from '../theme/EditorTheme'
import { sanitizeEditorConfig } from './sanitize'
export const defaultEditorFeatures: FeatureProvider[] = [
BoldTextFeature(),
ItalicTextFeature(),
UnderlineTextFeature(),
StrikethroughTextFeature(),
SubscriptTextFeature(),
SuperscriptTextFeature(),
InlineCodeTextFeature(),
ParagraphFeature(),
HeadingFeature({}),
AlignFeature(),
IndentFeature(),
UnoderedListFeature(),
OrderedListFeature(),
CheckListFeature(),
LinkFeature({}),
RelationshipFeature(),
BlockQuoteFeature(),
UploadFeature(),
//BlocksFeature(), // Adding this by default makes no sense if no blocks are defined
]
export const defaultEditorLexicalConfig: LexicalEditorConfig = {
namespace: 'lexical',
theme: LexicalEditorTheme,
}
export const defaultEditorConfig: EditorConfig = {
features: [
BoldTextFeature(),
ItalicTextFeature(),
UnderlineTextFeature(),
StrikethroughTextFeature(),
SubscriptTextFeature(),
SuperscriptTextFeature(),
InlineCodeTextFeature(),
ParagraphFeature(),
HeadingFeature({}),
AlignFeature(),
IndentFeature(),
UnoderedListFeature(),
OrderedListFeature(),
CheckListFeature(),
LinkFeature({}),
RelationshipFeature(),
BlockQuoteFeature(),
UploadFeature(),
//BlocksFeature(), // Adding this by default makes no sense if no blocks are defined
],
lexical: {
namespace: 'lexical',
theme: LexicalEditorTheme,
},
features: defaultEditorFeatures,
lexical: defaultEditorLexicalConfig,
}
export const defaultSanitizedEditorConfig: SanitizedEditorConfig =

View File

@@ -1,27 +1,51 @@
import type { EditorConfig as LexicalEditorConfig } from 'lexical/LexicalEditor'
import type { RichTextAdapter } from 'payload/types'
import { withMergedProps } from 'payload/components/utilities'
import type { FeatureProvider } from './field/features/types'
import type { EditorConfig, SanitizedEditorConfig } from './field/lexical/config/types'
import type { AdapterProps } from './types'
import { RichTextCell } from './cell'
import { RichTextField } from './field'
import { defaultEditorConfig, defaultSanitizedEditorConfig } from './field/lexical/config/default'
import {
defaultEditorFeatures,
defaultEditorLexicalConfig,
defaultSanitizedEditorConfig,
} from './field/lexical/config/default'
import { sanitizeEditorConfig } from './field/lexical/config/sanitize'
import { cloneDeep } from './field/lexical/utils/cloneDeep'
import { richTextRelationshipPromise } from './populate/richTextRelationshipPromise'
import { richTextValidateHOC } from './validate'
export function lexicalEditor({
userConfig,
}: {
userConfig?: (defaultEditorConfig: EditorConfig) => EditorConfig
}): RichTextAdapter<AdapterProps> {
const finalSanitizedEditorConfig: SanitizedEditorConfig =
userConfig == null || typeof userConfig != 'function'
? cloneDeep(defaultSanitizedEditorConfig)
: sanitizeEditorConfig(userConfig(cloneDeep(defaultEditorConfig)))
export type LexicalEditorProps = {
features?:
| (({ defaultFeatures }: { defaultFeatures: FeatureProvider[] }) => FeatureProvider[])
| FeatureProvider[]
lexical?: LexicalEditorConfig
}
export function lexicalEditor(props?: LexicalEditorProps): RichTextAdapter<AdapterProps> {
let finalSanitizedEditorConfig: SanitizedEditorConfig = null
if (!props || (!props.features && !props.lexical)) {
finalSanitizedEditorConfig = cloneDeep(defaultSanitizedEditorConfig)
} else {
let features: FeatureProvider[] =
props.features && typeof props.features === 'function'
? props.features({ defaultFeatures: cloneDeep(defaultEditorFeatures) })
: (props.features as FeatureProvider[])
if (!features) {
features = cloneDeep(defaultEditorFeatures)
}
const lexical: LexicalEditorConfig = props.lexical || cloneDeep(defaultEditorLexicalConfig)
finalSanitizedEditorConfig = sanitizeEditorConfig({
features,
lexical,
})
}
return {
CellComponent: withMergedProps({
@@ -88,9 +112,11 @@ export { CheckListFeature } from './field/features/lists/CheckList'
export { OrderedListFeature } from './field/features/lists/OrderedList'
export { UnoderedListFeature } from './field/features/lists/UnorderedList'
export type {
AfterReadPromise,
Feature,
FeatureProvider,
FeatureProviderMap,
NodeValidation,
ResolvedFeature,
ResolvedFeatureMap,
SanitizedFeatures,
@@ -100,7 +126,12 @@ export {
EditorConfigProvider,
useEditorConfigContext,
} from './field/lexical/config/EditorConfigProvider'
export { defaultEditorConfig, defaultSanitizedEditorConfig } from './field/lexical/config/default'
export {
defaultEditorConfig,
defaultEditorFeatures,
defaultEditorLexicalConfig,
defaultSanitizedEditorConfig,
} from './field/lexical/config/default'
export { loadFeatures, sortFeaturesForOptimalLoading } from './field/lexical/config/loader'
export { sanitizeEditorConfig, sanitizeFeatures } from './field/lexical/config/sanitize'
// export SanitizedEditorConfig

View File

@@ -24,7 +24,7 @@ export const UploadAndRichTextBlock: Block = {
{
name: 'richText',
type: 'richText',
editor: lexicalEditor({}),
editor: lexicalEditor(),
},
],
slug: 'uploadAndRichText',

View File

@@ -31,59 +31,48 @@ const RichTextFields: CollectionConfig = {
type: 'richText',
required: true,
editor: lexicalEditor({
userConfig(defaultEditorConfig) {
defaultEditorConfig.features.push(TreeviewFeature())
defaultEditorConfig.features.push(
LinkFeature({
fields: [
{
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.',
},
},
],
}),
)
defaultEditorConfig.features.push(
UploadFeature({
collections: {
uploads: {
fields: [
{
name: 'caption',
type: 'richText',
editor: lexicalEditor({}),
},
],
features: ({ defaultFeatures }) => [
...defaultFeatures,
TreeviewFeature(),
LinkFeature({
fields: [
{
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.',
},
},
}),
)
defaultEditorConfig.features.push(
BlocksFeature({
blocks: [TextBlock, UploadAndRichTextBlock],
}),
)
return defaultEditorConfig
},
],
}),
UploadFeature({
collections: {
uploads: {
fields: [
{
name: 'caption',
type: 'richText',
editor: lexicalEditor(),
},
],
},
},
}),
BlocksFeature({
blocks: [TextBlock, UploadAndRichTextBlock],
}),
],
}),
},
{
name: 'richTextLexical',
type: 'richText',
editor: lexicalEditor({
userConfig(defaultEditorConfig) {
defaultEditorConfig.features.push(TreeviewFeature())
return defaultEditorConfig
},
features: ({ defaultFeatures }) => [...defaultFeatures, TreeviewFeature()],
}),
},
{