Files
payload/packages/richtext-lexical/src/field/features/Blocks/index.ts
Alessio Gravili 5de347ffff feat(richtext-lexical)!: lazy import React components to prevent client-only code from leaking into the server (#4290)
* chore(richtext-lexical): lazy import all React things

* chore(richtext-lexical): use useMemo for lazy-loaded React Components to prevent lag and flashes when parent component re-renders

* chore: make exportPointerFiles.ts script usable for other packages as well by hoisting it up to the workspace root and making it configurable

* chore(richtext-lexical): make sure no client-side code is imported by default from Features

* chore(richtext-lexical): remove unnecessary scss files

* chore(richtext-lexical): adjust package.json exports

* chore(richtext-*): lazy-import Field & Cell Components, move Client-only exports to /components subpath export

* chore(richtext-lexical): make sure nothing client-side is directly exported from the / subpath export anymore

* add missing imports

* chore: remove breaking changes for Slate

* LazyCellComponent & LazyFieldComponent
2023-12-06 14:20:18 +01:00

84 lines
2.7 KiB
TypeScript

import type { Block } from 'payload/types'
import { baseBlockFields } from 'payload/config'
import { formatLabels, getTranslation } from 'payload/utilities'
import type { FeatureProvider } from '../types'
import { SlashMenuOption } from '../../lexical/plugins/SlashMenu/LexicalTypeaheadMenuPlugin/types'
import { BlockNode } from './nodes/BlocksNode'
import { INSERT_BLOCK_COMMAND } from './plugin/commands'
import { blockPopulationPromiseHOC } from './populationPromise'
import { blockValidationHOC } from './validate'
export type BlocksFeatureProps = {
blocks: Block[]
}
export const BlocksFeature = (props?: BlocksFeatureProps): FeatureProvider => {
// Sanitization taken from payload/src/fields/config/sanitize.ts
if (props?.blocks?.length) {
props.blocks = props.blocks.map((block) => {
return {
...block,
fields: block.fields.concat(baseBlockFields),
labels: !block.labels ? formatLabels(block.slug) : block.labels,
}
})
// unsanitizedBlock.fields are sanitized in the React component and not here.
// That's because we do not have access to the payload config here.
}
return {
feature: () => {
return {
nodes: [
{
node: BlockNode,
populationPromises: [blockPopulationPromiseHOC(props)],
type: BlockNode.getType(),
validations: [blockValidationHOC(props)],
},
],
plugins: [
{
Component: () =>
// @ts-expect-error
import('./plugin').then((module) => module.BlocksPlugin),
position: 'normal',
},
],
props: props,
slashMenu: {
options: [
{
displayName: 'Blocks',
key: 'blocks',
options: [
...props.blocks.map((block) => {
return new SlashMenuOption('block-' + block.slug, {
Icon: () =>
// @ts-expect-error
import('../../lexical/ui/icons/Block').then((module) => module.BlockIcon),
displayName: ({ i18n }) => {
return getTranslation(block.labels.singular, i18n)
},
keywords: ['block', 'blocks', block.slug],
onSelect: ({ editor }) => {
editor.dispatchCommand(INSERT_BLOCK_COMMAND, {
id: null,
blockName: '',
blockType: block.slug,
})
},
})
}),
],
},
],
},
}
},
key: 'blocks',
}
}