Skip to content

Commit fca4ee9

Browse files
authored
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 #7579 The problem was that multiple richtext editors shared the same drawer slugs for the table and inline block drawers.
1 parent 352ed0e commit fca4ee9

File tree

4 files changed

+54
-23
lines changed
  • packages/richtext-lexical/src/features
  • test/fields/collections/Lexical/e2e/main

4 files changed

+54
-23
lines changed

packages/richtext-lexical/src/features/blocks/client/plugin/index.tsx

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import type { BlockFieldClient } from 'payload'
55
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
66
import { $insertNodeToNearestRoot, $wrapNodeInElement, mergeRegister } from '@lexical/utils'
77
import { getTranslation } from '@payloadcms/translations'
8-
import { useFieldProps, useModal, useTranslation } from '@payloadcms/ui'
8+
import {
9+
formatDrawerSlug,
10+
useEditDepth,
11+
useFieldProps,
12+
useModal,
13+
useTranslation,
14+
} from '@payloadcms/ui'
915
import {
1016
$createParagraphNode,
1117
$getNodeByKey,
@@ -37,8 +43,6 @@ import {
3743

3844
export type InsertBlockPayload = Exclude<BlockFields, 'id'>
3945

40-
const drawerSlug = 'lexical-inlineBlocks-create'
41-
4246
export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
4347
const [editor] = useLexicalComposerContext()
4448
const { closeModal, toggleModal } = useModal()
@@ -47,22 +51,18 @@ export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
4751
const [targetNodeKey, setTargetNodeKey] = useState<null | string>(null)
4852
const { i18n, t } = useTranslation<string, any>()
4953
const { schemaPath } = useFieldProps()
54+
const { uuid } = useEditorConfigContext()
55+
const editDepth = useEditDepth()
56+
57+
const drawerSlug = formatDrawerSlug({
58+
slug: `lexical-inlineBlocks-create-` + uuid,
59+
depth: editDepth,
60+
})
5061

5162
const {
5263
field: { richTextComponentMap },
5364
} = useEditorConfigContext()
5465

55-
const schemaFieldsPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.lexical_inline_blocks.${blockFields?.blockType}`
56-
57-
const componentMapRenderedBlockPath = `lexical_internal_feature.blocks.fields.lexical_inline_blocks`
58-
const blocksField: BlockFieldClient = richTextComponentMap.has(componentMapRenderedBlockPath)
59-
? richTextComponentMap.get(componentMapRenderedBlockPath)[0]
60-
: null
61-
62-
const clientBlock = blocksField
63-
? blocksField.blocks.find((block) => block.slug === blockFields?.blockType)
64-
: null
65-
6666
useEffect(() => {
6767
if (!editor.hasNodes([BlockNode])) {
6868
throw new Error('BlocksPlugin: BlocksNode not registered on editor')
@@ -158,7 +158,22 @@ export const BlocksPlugin: PluginComponent<BlocksFeatureClientProps> = () => {
158158
COMMAND_PRIORITY_EDITOR,
159159
),
160160
)
161-
}, [editor, targetNodeKey, toggleModal])
161+
}, [editor, targetNodeKey, toggleModal, drawerSlug])
162+
163+
if (!blockFields) {
164+
return null
165+
}
166+
167+
const schemaFieldsPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.lexical_inline_blocks.${blockFields?.blockType}`
168+
169+
const componentMapRenderedBlockPath = `lexical_internal_feature.blocks.fields.lexical_inline_blocks`
170+
const blocksField: BlockFieldClient = richTextComponentMap.has(componentMapRenderedBlockPath)
171+
? richTextComponentMap.get(componentMapRenderedBlockPath)[0]
172+
: null
173+
174+
const clientBlock = blocksField
175+
? blocksField.blocks.find((block) => block.slug === blockFields?.blockType)
176+
: null
162177

163178
if (!blocksField) {
164179
return null

packages/richtext-lexical/src/features/experimental_table/client/plugins/TablePlugin/index.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
1414
import { TablePlugin as LexicalReactTablePlugin } from '@lexical/react/LexicalTablePlugin'
1515
import { INSERT_TABLE_COMMAND, TableNode } from '@lexical/table'
1616
import { mergeRegister } from '@lexical/utils'
17-
import { useModal } from '@payloadcms/ui'
17+
import { formatDrawerSlug, useEditDepth, useModal } from '@payloadcms/ui'
1818
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'
1919
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
2020
import * as React from 'react'
2121

2222
import type { PluginComponent } from '../../../../typesClient.js'
2323

24+
import { useEditorConfigContext } from '../../../../../lexical/config/client/EditorConfigProvider.js'
2425
import { FieldsDrawer } from '../../../../../utilities/fieldsDrawer/Drawer.js'
2526
import './index.scss'
2627

@@ -52,7 +53,6 @@ export const CellContext = createContext<CellContextShape>({
5253
// Empty
5354
},
5455
})
55-
const drawerSlug = 'lexical-table-create'
5656

5757
export function TableContext({ children }: { children: JSX.Element }) {
5858
const [contextValue, setContextValue] = useState<{
@@ -84,6 +84,13 @@ export const TablePlugin: PluginComponent = () => {
8484
const [editor] = useLexicalComposerContext()
8585
const cellContext = useContext(CellContext)
8686
const { closeModal, toggleModal } = useModal()
87+
const editDepth = useEditDepth()
88+
const { uuid } = useEditorConfigContext()
89+
90+
const drawerSlug = formatDrawerSlug({
91+
slug: 'lexical-table-create-' + uuid,
92+
depth: editDepth,
93+
})
8794

8895
useEffect(() => {
8996
if (!editor.hasNodes([TableNode])) {

packages/richtext-lexical/src/features/upload/client/component/index.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {
99
Button,
1010
DrawerToggler,
1111
File,
12+
formatDrawerSlug,
1213
useConfig,
1314
useDocumentDrawer,
14-
useDrawerSlug,
15+
useEditDepth,
1516
useModal,
1617
usePayloadAPI,
1718
useTranslation,
@@ -25,7 +26,7 @@ import {
2526
KEY_BACKSPACE_COMMAND,
2627
KEY_DELETE_COMMAND,
2728
} from 'lexical'
28-
import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'
29+
import React, { useCallback, useEffect, useId, useReducer, useRef, useState } from 'react'
2930

3031
import type { ClientComponentProps } from '../../../typesClient.js'
3132
import type { UploadData } from '../../server/nodes/UploadNode.js'
@@ -65,7 +66,8 @@ const Component: React.FC<ElementProps> = (props) => {
6566
} = useConfig()
6667
const uploadRef = useRef<HTMLDivElement | null>(null)
6768
const { closeModal } = useModal()
68-
69+
const { uuid } = useEditorConfigContext()
70+
const editDepth = useEditDepth()
6971
const [editor] = useLexicalComposerContext()
7072
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)
7173

@@ -77,7 +79,12 @@ const Component: React.FC<ElementProps> = (props) => {
7779
collections.find((coll) => coll.slug === relationTo),
7880
)
7981

80-
const drawerSlug = useDrawerSlug('upload-drawer')
82+
const componentID = useId()
83+
84+
const drawerSlug = formatDrawerSlug({
85+
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
86+
depth: editDepth,
87+
})
8188

8289
const [DocumentDrawer, DocumentDrawerToggler, { closeDrawer }] = useDocumentDrawer({
8390
id: value,

test/fields/collections/Lexical/e2e/main/e2e.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,9 @@ describe('lexicalMain', () => {
482482
// Click on button with class lexical-upload__upload-drawer-toggler
483483
await newUploadNode.locator('.lexical-upload__upload-drawer-toggler').first().click()
484484

485-
const uploadExtraFieldsDrawer = page.locator('dialog[id^=drawer_1_upload-drawer-]').first()
485+
const uploadExtraFieldsDrawer = page
486+
.locator('dialog[id^=drawer_1_lexical-upload-drawer-]')
487+
.first()
486488
await expect(uploadExtraFieldsDrawer).toBeVisible()
487489
await wait(500)
488490

@@ -508,7 +510,7 @@ describe('lexicalMain', () => {
508510
await expect(reloadedUploadNode).toBeVisible()
509511
await reloadedUploadNode.locator('.lexical-upload__upload-drawer-toggler').first().click()
510512
const reloadedUploadExtraFieldsDrawer = page
511-
.locator('dialog[id^=drawer_1_upload-drawer-]')
513+
.locator('dialog[id^=drawer_1_lexical-upload-drawer-]')
512514
.first()
513515
await expect(reloadedUploadExtraFieldsDrawer).toBeVisible()
514516
await wait(500)

0 commit comments

Comments
 (0)