Extending Payload's
BlocksFeatureClientto override the plugin, the command dispatch for
INSERT_BLOCK_COMMANDfails (even with identical plugin):
import { BlocksFeatureClient as BlocksFeatureClientPayload } from '@payloadcms/richtext-lexical/client'
import { BlocksPlugin } from './plugins/BlocksPlugin' // copypaste of original
export const BlocksFeatureClient = createClientFeature(args => {
const clientFeaturePayload = BlocksFeatureClientPayload(args)
const feature =
typeof clientFeaturePayload.feature === 'function'
? clientFeaturePayload.feature(args)
: clientFeaturePayload.feature
return {
...feature,
plugins: [
{
Component: BlocksPlugin,
position: 'normal',
}
]
}
})Odd thing is returning just the feature like so works:
return {
...feature
}Suggesting that merely extending it what's breaking it.
Debugging we find that
- The returned feature seems well formed, identical to the unaltered feature.
- The
slashMenuproperty on the returned feature (where the
INSERT_BLOCK_COMMANDis invoked) is preserved.
- The plugin is invoked, but:
- Breakpoints in the
editor.update()invoked on
INSERT_BLOCK_COMMANDare not hit.
Please help - stuck on this on the 3rd day 🙏
Hi
@360823574644129795, could I ask you to take a look at this when you get a minute?
import { BlocksPlugin } from './plugins/BlocksPlugin' // copypaste of originalIf you copied that file from the original, it probably means that you are using Lexical imports instead of
@payloadcms/richtext-lexical/lexical/..., is that right?
If so, try replacing the imports. It is likely that we are using a different version of Lexical than the one you have installed.
I'm using the Payload proxies exactly as in the Payload plugin, no direct imports from lexical packages there
My server* feature override FWIW:
export const BlocksFeature = (props: BlocksFeatureProps): FeatureProviderServer => {
const serverFeaturePayload = BlocksFeaturePayload({
blocks: props.blocks,
inlineBlocks: props.inlineBlocks
})
const feature = async (args: ServerFeatureProps<BlocksFeatureProps>) => {
const featureResult =
typeof serverFeaturePayload.feature === 'function'
? await serverFeaturePayload.feature(args)
: serverFeaturePayload.feature
return {
...featureResult,
ClientFeature: '@/_lib/lexical/features/blocks/feature.client#BlocksFeatureClient',
}
}
const featureProvider = createServerFeature<any, any, any>({
...serverFeaturePayload,
feature: feature
})
return featureProvider()
}What's interesting is the plugin override seems to work. I'm hitting breakpoints in it, just not in the listener for
INSERT_BLOCK_COMMAND. It's like the listener is never registered.
if you're using the same react & lexical versions, I don't know why it wouldn't work
Can you show the code for your plugin?
Ah and where are you getting the
INSERT_BLOCK_COMMANDfrom?
not sure how exactly lexical finds the correct listener for a dispatched command
if it compares the object references instead of the command
typestring value, it might not work if you re-define that command
My React versions are pinned to the recommended 19-rc and I don't have any lexical packages installed.
The commands are just copied in verbatim,
'use client'
import { LexicalCommand, createCommand } from "@payloadcms/richtext-lexical/lexical"
import { InsertBlockPayload } from "./BlocksPlugin"
export const INSERT_BLOCK_COMMAND: LexicalCommand<InsertBlockPayload> =
createCommand('INSERT_BLOCK_COMMAND')
export const INSERT_INLINE_BLOCK_COMMAND: LexicalCommand<Partial<InsertBlockPayload>> =
createCommand('INSERT_INLINE_BLOCK_COMMAND')Here's the plugin:
'use client'
import { formatDrawerSlug, useEditDepth } from '@payloadcms/ui'
import { useEffect, useState } from 'react'
import { INSERT_BLOCK_COMMAND, INSERT_INLINE_BLOCK_COMMAND } from './commands'
import { BlockFields, PluginComponent } from '@payloadcms/richtext-lexical'
import { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext'
import { $createBlockNode, $createInlineBlockNode, $isInlineBlockNode, BlockNode, useEditorConfigContext, useLexicalDrawer } from '@payloadcms/richtext-lexical/client'
import { $insertNodeToNearestRoot, $wrapNodeInElement, mergeRegister } from '@payloadcms/richtext-lexical/lexical/utils'
import {
$createParagraphNode,
$getNodeByKey,
$getPreviousSelection,
$getSelection,
$insertNodes,
$isParagraphNode,
$isRangeSelection,
$isRootOrShadowRoot,
COMMAND_PRIORITY_EDITOR
} from '@payloadcms/richtext-lexical/lexical'
import type { BlockFieldsOptionalID } from '../nodes/ServerBlockNode'
export type InsertBlockPayload = BlockFieldsOptionalID
export const BlocksPlugin: PluginComponent = () => {
const [editor] = useLexicalComposerContext()
const [targetNodeKey, setTargetNodeKey] = useState<null | string>(null)
const { setCreatedInlineBlock, uuid } = useEditorConfigContext()
const editDepth = useEditDepth()
const drawerSlug = formatDrawerSlug({
slug: `lexical-inlineBlocks-create-` + uuid,
depth: editDepth,
})
const { toggleDrawer } = useLexicalDrawer(drawerSlug, true)
useEffect(() => {
if (!editor.hasNodes([BlockNode])) {
throw new Error('BlocksPlugin: BlocksNode not registered on editor')
} return mergeRegister(
editor.registerCommand<InsertBlockPayload>(
INSERT_BLOCK_COMMAND,
(payload: InsertBlockPayload) => {
editor.update(() => {
const selection = $getSelection() || $getPreviousSelection()
if ($isRangeSelection(selection)) {
const blockNode = $createBlockNode(payload)
// Insert blocks node BEFORE potentially removing focusNode, as $insertNodeToNearestRoot errors if the focusNode doesn't exist
$insertNodeToNearestRoot(blockNode)
const { focus } = selection
const focusNode = focus.getNode()
// First, delete currently selected node if it's an empty paragraph and if there are sufficient
// paragraph nodes (more than 1) left in the parent node, so that we don't "trap" the user
if (
$isParagraphNode(focusNode) &&
focusNode.getTextContentSize() === 0 &&
focusNode
.getParentOrThrow()
.getChildren()
.filter((node) => $isParagraphNode(node)).length > 1
) {
focusNode.remove()
}
}
})
return true
},
COMMAND_PRIORITY_EDITOR,
),
...
return null
}My React versions are pinned to the recommended 19-rc
which one exactly?
And you are defining the
INSERT_BLOCK_COMMANDyourself in that
commandsfile, right?
I think that's why it doesn't work
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",just checked, and lexical checks for command reference equality - so the command that's dispatched by us will be a different one
Ahh
Explains it
change those to just "19.0.0" - no need to use the rc versions anymore
Oh okay thx
I'll export those commands for you rn
Thank you so much
you're welcome!
Super appreciated!
here's a release you can use with the commands exported from
@967091941873426493/richtext-lexical/client:
3.24.0-canary.f229d8dYep I got it, thanks 😊
Error: Mismatching "payload" dependency versions found: @payloadcms/richtext-lexical@3.24.0-canary.f229d8d (Please change this to 3.23.0)Just go in your package.json and set all payload packages to the same version, reinstall
Star
Discord
online
Get dedicated engineering support directly from the Payload team.