Skip to content

Commit 181f82f

Browse files
authored
feat(richtext-lexical): implement relationship node click and delete/backspace handling (#6147)
1 parent 6a9cde2 commit 181f82f

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

packages/richtext-lexical/src/field/features/relationship/nodes/components/RelationshipComponent.tsx

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@ import type { ElementFormatType } from 'lexical'
33

44
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
55
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection.js'
6+
import { mergeRegister } from '@lexical/utils'
67
import { getTranslation } from '@payloadcms/translations'
78
import { Button } from '@payloadcms/ui/elements/Button'
89
import { useDocumentDrawer } from '@payloadcms/ui/elements/DocumentDrawer'
910
import usePayloadAPI from '@payloadcms/ui/hooks/usePayloadAPI'
1011
import { useConfig } from '@payloadcms/ui/providers/Config'
1112
import { useTranslation } from '@payloadcms/ui/providers/Translation'
13+
import {
14+
$getSelection,
15+
$isNodeSelection,
16+
CLICK_COMMAND,
17+
COMMAND_PRIORITY_LOW,
18+
KEY_BACKSPACE_COMMAND,
19+
KEY_DELETE_COMMAND,
20+
} from 'lexical'
1221
import { $getNodeByKey } from 'lexical'
13-
import React, { useCallback, useReducer, useState } from 'react'
22+
import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'
1423

1524
import type { RelationshipData } from '../RelationshipNode.js'
1625

1726
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'
1827
import { INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND } from '../../drawer/commands.js'
28+
import { $isRelationshipNode } from '../RelationshipNode.js'
1929
import './index.scss'
2030

2131
const baseClass = 'lexical-relationship'
@@ -39,6 +49,8 @@ const Component: React.FC<Props> = (props) => {
3949
nodeKey,
4050
} = props
4151

52+
const relationshipElemRef = useRef<HTMLDivElement | null>(null)
53+
4254
const [editor] = useLexicalComposerContext()
4355
const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey)
4456
const { field } = useEditorConfigContext()
@@ -83,10 +95,57 @@ const Component: React.FC<Props> = (props) => {
8395
[cacheBust, setParams, closeDrawer],
8496
)
8597

98+
const onDelete = useCallback(
99+
(payload: KeyboardEvent) => {
100+
if (isSelected && $isNodeSelection($getSelection())) {
101+
const event: KeyboardEvent = payload
102+
event.preventDefault()
103+
const node = $getNodeByKey(nodeKey)
104+
if ($isRelationshipNode(node)) {
105+
node.remove()
106+
return true
107+
}
108+
}
109+
return false
110+
},
111+
[isSelected, nodeKey],
112+
)
113+
const onClick = useCallback(
114+
(payload: MouseEvent) => {
115+
const event = payload
116+
// Check if relationshipElemRef.target or anything WITHIN relationshipElemRef.target was clicked
117+
if (
118+
event.target === relationshipElemRef.current ||
119+
relationshipElemRef.current?.contains(event.target as Node)
120+
) {
121+
if (event.shiftKey) {
122+
setSelected(!isSelected)
123+
} else {
124+
clearSelection()
125+
setSelected(true)
126+
}
127+
return true
128+
}
129+
130+
return false
131+
},
132+
[isSelected, setSelected, clearSelection],
133+
)
134+
135+
useEffect(() => {
136+
return mergeRegister(
137+
editor.registerCommand<MouseEvent>(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW),
138+
139+
editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW),
140+
editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW),
141+
)
142+
}, [clearSelection, editor, isSelected, nodeKey, onDelete, setSelected, onClick])
143+
86144
return (
87145
<div
88146
className={[baseClass, isSelected && `${baseClass}--selected`].filter(Boolean).join(' ')}
89147
contentEditable={false}
148+
ref={relationshipElemRef}
90149
>
91150
<div className={`${baseClass}__wrap`}>
92151
<p className={`${baseClass}__label`}>

0 commit comments

Comments
 (0)