Skip to content

Commit 801ab5a

Browse files
committed
fix: ensure image is inserted at correct drop selection
1 parent 1d2ebbc commit 801ab5a

File tree

1 file changed

+44
-2
lines changed
  • packages/richtext-lexical/src/features/upload/client/plugin

1 file changed

+44
-2
lines changed

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ import { $dfsIterator, $insertNodeToNearestRoot, mergeRegister } from '@lexical/
66
import { useBulkUpload, useConfig, useEffectEvent, useModal } from '@payloadcms/ui'
77
import ObjectID from 'bson-objectid'
88
import {
9+
$createRangeSelection,
910
$getPreviousSelection,
1011
$getSelection,
1112
$isParagraphNode,
1213
$isRangeSelection,
14+
$setSelection,
1315
COMMAND_PRIORITY_EDITOR,
1416
COMMAND_PRIORITY_LOW,
1517
createCommand,
1618
DROP_COMMAND,
19+
getDOMSelectionFromTarget,
20+
isHTMLElement,
1721
PASTE_COMMAND,
1822
} from 'lexical'
1923
import React, { useEffect } from 'react'
@@ -28,6 +32,39 @@ import { $createUploadNode, UploadNode } from '../nodes/UploadNode.js'
2832

2933
export type InsertUploadPayload = Readonly<Omit<UploadData, 'id'> & Partial<Pick<UploadData, 'id'>>>
3034

35+
declare global {
36+
interface DragEvent {
37+
rangeOffset?: number
38+
rangeParent?: Node
39+
}
40+
}
41+
42+
function canDropImage(event: DragEvent): boolean {
43+
const target = event.target
44+
return !!(
45+
isHTMLElement(target) &&
46+
!target.closest('code, span.editor-image') &&
47+
isHTMLElement(target.parentElement) &&
48+
target.parentElement.closest('div.ContentEditable__root')
49+
)
50+
}
51+
52+
function getDragSelection(event: DragEvent): null | Range | undefined {
53+
// Source: https://github.com/AlessioGr/lexical/blob/main/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx
54+
let range
55+
const domSelection = getDOMSelectionFromTarget(event.target)
56+
if (document.caretRangeFromPoint) {
57+
range = document.caretRangeFromPoint(event.clientX, event.clientY)
58+
} else if (event.rangeParent && domSelection !== null) {
59+
domSelection.collapse(event.rangeParent, event.rangeOffset || 0)
60+
range = domSelection.getRangeAt(0)
61+
} else {
62+
throw Error(`Cannot get the selection when dragging`)
63+
}
64+
65+
return range
66+
}
67+
3168
export const INSERT_UPLOAD_COMMAND: LexicalCommand<InsertUploadPayload> =
3269
createCommand('INSERT_UPLOAD_COMMAND')
3370

@@ -300,9 +337,14 @@ export const UploadPlugin: PluginComponent<UploadFeaturePropsClient> = () => {
300337

301338
// Insert a PendingUploadNode for each image
302339
editor.update(() => {
303-
const selection = $getSelection() || $getPreviousSelection()
340+
if (canDropImage(event)) {
341+
const range = getDragSelection(event)
342+
const selection = $createRangeSelection()
343+
if (range !== null && range !== undefined) {
344+
selection.applyDOMRange(range)
345+
}
346+
$setSelection(selection)
304347

305-
if ($isRangeSelection(selection)) {
306348
for (const file of files) {
307349
const pendingUploadNode = new PendingUploadNode({
308350
data: {

0 commit comments

Comments
 (0)