fix(richtext-lexical): inline blocks and tables not functioning correctly if they are used in more than one editor on the same page (#7665)
Fixes https://github.com/payloadcms/payload/issues/7579 The problem was that multiple richtext editors shared the same drawer slugs for the table and inline block drawers.
This commit is contained in:
@@ -5,7 +5,13 @@ import type { BlockFieldClient } from 'payload'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
|
||||
import { $insertNodeToNearestRoot, $wrapNodeInElement, mergeRegister } from '@lexical/utils'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import { useFieldProps, useModal, useTranslation } from '@payloadcms/ui'
|
||||
import {
|
||||
formatDrawerSlug,
|
||||
useEditDepth,
|
||||
useFieldProps,
|
||||
useModal,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import {
|
||||
$createParagraphNode,
|
||||
$getNodeByKey,
|
||||
@@ -37,8 +43,6 @@ import {
|
||||
|
||||
export type InsertBlockPayload = Exclude<BlockFields, 'id'>
|
||||
|
||||
const drawerSlug = 'lexical-inlineBlocks-create'
|
||||
|
||||
export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const { closeModal, toggleModal } = useModal()
|
||||
@@ -47,22 +51,18 @@ export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
|
||||
const [targetNodeKey, setTargetNodeKey] = useState<null | string>(null)
|
||||
const { i18n, t } = useTranslation<string, any>()
|
||||
const { schemaPath } = useFieldProps()
|
||||
const { uuid } = useEditorConfigContext()
|
||||
const editDepth = useEditDepth()
|
||||
|
||||
const drawerSlug = formatDrawerSlug({
|
||||
slug: `lexical-inlineBlocks-create-` + uuid,
|
||||
depth: editDepth,
|
||||
})
|
||||
|
||||
const {
|
||||
field: { richTextComponentMap },
|
||||
} = useEditorConfigContext()
|
||||
|
||||
const schemaFieldsPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.lexical_inline_blocks.${blockFields?.blockType}`
|
||||
|
||||
const componentMapRenderedBlockPath = `lexical_internal_feature.blocks.fields.lexical_inline_blocks`
|
||||
const blocksField: BlockFieldClient = richTextComponentMap.has(componentMapRenderedBlockPath)
|
||||
? richTextComponentMap.get(componentMapRenderedBlockPath)[0]
|
||||
: null
|
||||
|
||||
const clientBlock = blocksField
|
||||
? blocksField.blocks.find((block) => block.slug === blockFields?.blockType)
|
||||
: null
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([BlockNode])) {
|
||||
throw new Error('BlocksPlugin: BlocksNode not registered on editor')
|
||||
@@ -158,7 +158,22 @@ export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
),
|
||||
)
|
||||
}, [editor, targetNodeKey, toggleModal])
|
||||
}, [editor, targetNodeKey, toggleModal, drawerSlug])
|
||||
|
||||
if (!blockFields) {
|
||||
return null
|
||||
}
|
||||
|
||||
const schemaFieldsPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.lexical_inline_blocks.${blockFields?.blockType}`
|
||||
|
||||
const componentMapRenderedBlockPath = `lexical_internal_feature.blocks.fields.lexical_inline_blocks`
|
||||
const blocksField: BlockFieldClient = richTextComponentMap.has(componentMapRenderedBlockPath)
|
||||
? richTextComponentMap.get(componentMapRenderedBlockPath)[0]
|
||||
: null
|
||||
|
||||
const clientBlock = blocksField
|
||||
? blocksField.blocks.find((block) => block.slug === blockFields?.blockType)
|
||||
: null
|
||||
|
||||
if (!blocksField) {
|
||||
return null
|
||||
|
||||
@@ -14,13 +14,14 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
||||
import { TablePlugin as LexicalReactTablePlugin } from '@lexical/react/LexicalTablePlugin'
|
||||
import { INSERT_TABLE_COMMAND, TableNode } from '@lexical/table'
|
||||
import { mergeRegister } from '@lexical/utils'
|
||||
import { useModal } from '@payloadcms/ui'
|
||||
import { formatDrawerSlug, useEditDepth, useModal } from '@payloadcms/ui'
|
||||
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import * as React from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../../typesClient.js'
|
||||
|
||||
import { useEditorConfigContext } from '../../../../../lexical/config/client/EditorConfigProvider.js'
|
||||
import { FieldsDrawer } from '../../../../../utilities/fieldsDrawer/Drawer.js'
|
||||
import './index.scss'
|
||||
|
||||
@@ -52,7 +53,6 @@ export const CellContext = createContext<CellContextShape>({
|
||||
// Empty
|
||||
},
|
||||
})
|
||||
const drawerSlug = 'lexical-table-create'
|
||||
|
||||
export function TableContext({ children }: { children: JSX.Element }) {
|
||||
const [contextValue, setContextValue] = useState<{
|
||||
@@ -84,6 +84,13 @@ export const TablePlugin: PluginComponent = () => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const cellContext = useContext(CellContext)
|
||||
const { closeModal, toggleModal } = useModal()
|
||||
const editDepth = useEditDepth()
|
||||
const { uuid } = useEditorConfigContext()
|
||||
|
||||
const drawerSlug = formatDrawerSlug({
|
||||
slug: 'lexical-table-create-' + uuid,
|
||||
depth: editDepth,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([TableNode])) {
|
||||
|
||||
@@ -9,9 +9,10 @@ import {
|
||||
Button,
|
||||
DrawerToggler,
|
||||
File,
|
||||
formatDrawerSlug,
|
||||
useConfig,
|
||||
useDocumentDrawer,
|
||||
useDrawerSlug,
|
||||
useEditDepth,
|
||||
useModal,
|
||||
usePayloadAPI,
|
||||
useTranslation,
|
||||
@@ -25,7 +26,7 @@ import {
|
||||
KEY_BACKSPACE_COMMAND,
|
||||
KEY_DELETE_COMMAND,
|
||||
} from 'lexical'
|
||||
import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useId, useReducer, useRef, useState } from 'react'
|
||||
|
||||
import type { ClientComponentProps } from '../../../typesClient.js'
|
||||
import type { UploadData } from '../../server/nodes/UploadNode.js'
|
||||
@@ -65,7 +66,8 @@ const Component: React.FC<ElementProps> = (props) => {
|
||||
} = useConfig()
|
||||
const uploadRef = useRef<HTMLDivElement | null>(null)
|
||||
const { closeModal } = useModal()
|
||||
|
||||
const { uuid } = useEditorConfigContext()
|
||||
const editDepth = useEditDepth()
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)
|
||||
|
||||
@@ -77,7 +79,12 @@ const Component: React.FC<ElementProps> = (props) => {
|
||||
collections.find((coll) => coll.slug === relationTo),
|
||||
)
|
||||
|
||||
const drawerSlug = useDrawerSlug('upload-drawer')
|
||||
const componentID = useId()
|
||||
|
||||
const drawerSlug = formatDrawerSlug({
|
||||
slug: `lexical-upload-drawer-` + uuid + componentID, // There can be multiple upload components, each with their own drawer, in one single editor => separate them by componentID
|
||||
depth: editDepth,
|
||||
})
|
||||
|
||||
const [DocumentDrawer, DocumentDrawerToggler, { closeDrawer }] = useDocumentDrawer({
|
||||
id: value,
|
||||
|
||||
@@ -482,7 +482,9 @@ describe('lexicalMain', () => {
|
||||
// Click on button with class lexical-upload__upload-drawer-toggler
|
||||
await newUploadNode.locator('.lexical-upload__upload-drawer-toggler').first().click()
|
||||
|
||||
const uploadExtraFieldsDrawer = page.locator('dialog[id^=drawer_1_upload-drawer-]').first()
|
||||
const uploadExtraFieldsDrawer = page
|
||||
.locator('dialog[id^=drawer_1_lexical-upload-drawer-]')
|
||||
.first()
|
||||
await expect(uploadExtraFieldsDrawer).toBeVisible()
|
||||
await wait(500)
|
||||
|
||||
@@ -508,7 +510,7 @@ describe('lexicalMain', () => {
|
||||
await expect(reloadedUploadNode).toBeVisible()
|
||||
await reloadedUploadNode.locator('.lexical-upload__upload-drawer-toggler').first().click()
|
||||
const reloadedUploadExtraFieldsDrawer = page
|
||||
.locator('dialog[id^=drawer_1_upload-drawer-]')
|
||||
.locator('dialog[id^=drawer_1_lexical-upload-drawer-]')
|
||||
.first()
|
||||
await expect(reloadedUploadExtraFieldsDrawer).toBeVisible()
|
||||
await wait(500)
|
||||
|
||||
Reference in New Issue
Block a user