@@ -73,7 +73,7 @@ function Draggable(props: PlateElementProps) {
7373 const { children, editor, element, path } = props ;
7474 const blockSelectionApi = editor . getApi ( BlockSelectionPlugin ) . blockSelection ;
7575
76- const { isDragging, multiplePreviewRef , previewRef, handleRef } =
76+ const { isDragging, nodeRef , previewRef, handleRef } =
7777 useDraggable ( {
7878 element,
7979 onDropHandler : ( _ , { dragItem } ) => {
@@ -82,20 +82,25 @@ function Draggable(props: PlateElementProps) {
8282 if ( blockSelectionApi ) {
8383 blockSelectionApi . add ( id ) ;
8484 }
85- multiplePreviewRef . current ?. replaceChildren ( ) ;
85+ resetPreview ( ) ;
8686 } ,
8787 } ) ;
8888
8989 const isInColumn = path . length === 3 ;
9090 const isInTable = path . length === 4 ;
9191
92- const [ multiplePreviewTop , setMultiplePreviewTop ] = React . useState ( 0 ) ;
93- const [ isMultiple , setIsMultiple ] = React . useState ( false ) ;
92+ const [ previewTop , setPreviewTop ] = React . useState ( 0 ) ;
93+
94+ const resetPreview = ( ) => {
95+ if ( previewRef . current ) {
96+ previewRef . current . replaceChildren ( ) ;
97+ }
98+ }
9499
95100 // clear up virtual multiple preview when drag end
96101 React . useEffect ( ( ) => {
97- if ( ! isDragging && isMultiple ) {
98- multiplePreviewRef . current ?. replaceChildren ( ) ;
102+ if ( ! isDragging ) {
103+ resetPreview ( ) ;
99104 }
100105 // eslint-disable-next-line react-hooks/exhaustive-deps
101106 } , [ isDragging ] ) ;
@@ -141,10 +146,8 @@ function Draggable(props: PlateElementProps) {
141146 >
142147 < DragHandle
143148 isDragging = { isDragging }
144- isMultiple = { isMultiple }
145- multiplePreviewRef = { multiplePreviewRef }
146- setIsMultiple = { setIsMultiple }
147- setMultiplePreviewTop = { setMultiplePreviewTop }
149+ previewRef = { previewRef }
150+ setPreviewTop = { setPreviewTop }
148151 />
149152 </ Button >
150153 </ div >
@@ -153,13 +156,13 @@ function Draggable(props: PlateElementProps) {
153156 ) }
154157
155158 < div
156- ref = { multiplePreviewRef }
159+ ref = { previewRef }
157160 className = { cn ( 'absolute -left-0 hidden w-full' ) }
158- style = { { top : `${ - multiplePreviewTop } px` } }
161+ style = { { top : `${ - previewTop } px` } }
159162 contentEditable = { false }
160163 />
161164
162- < div ref = { previewRef } className = "slate-blockWrapper flow-root" >
165+ < div ref = { nodeRef } className = "slate-blockWrapper flow-root" >
163166 < MemoizedChildren > { children } </ MemoizedChildren >
164167 < DropLine />
165168 </ div >
@@ -202,16 +205,12 @@ function Gutter({
202205
203206const DragHandle = React . memo ( function DragHandle ( {
204207 isDragging,
205- isMultiple,
206- multiplePreviewRef,
207- setIsMultiple,
208- setMultiplePreviewTop,
208+ previewRef,
209+ setPreviewTop,
209210} : {
210211 isDragging : boolean ;
211- isMultiple : boolean ;
212- multiplePreviewRef : React . RefObject < HTMLDivElement | null > ;
213- setIsMultiple : ( isMultiple : boolean ) => void ;
214- setMultiplePreviewTop : ( top : number ) => void ;
212+ previewRef : React . RefObject < HTMLDivElement | null > ;
213+ setPreviewTop : ( top : number ) => void ;
215214} ) {
216215 const editor = useEditorRef ( ) ;
217216 const element = useElement ( ) ;
@@ -229,36 +228,37 @@ const DragHandle = React.memo(function DragHandle({
229228 onMouseDown = { ( e ) => {
230229 if ( e . button !== 0 || e . shiftKey ) return ; // Only left mouse button
231230
232- if ( isMultiple ) {
233- const elements = createDragPreviewElements ( editor ) ;
234- multiplePreviewRef . current ?. append ( ...elements ) ;
235- multiplePreviewRef . current ?. classList . remove ( 'hidden' ) ;
236- } else {
237- editor . setOption ( DndPlugin , 'draggingId' , null ) ;
238- return ;
239- }
231+ const elements = createDragPreviewElements ( editor , { currentBlock : element } ) ;
232+ previewRef . current ?. append ( ...elements ) ;
233+ previewRef . current ?. classList . remove ( 'hidden' ) ;
234+ editor . setOption ( DndPlugin , 'multiplePreviewRef' , previewRef ) ;
240235 } }
241236 onMouseEnter = { ( ) => {
242237 if ( isDragging ) return ;
243238
244- const isSelected = editor . getOption (
245- BlockSelectionPlugin ,
246- 'isSelected' ,
247- element . id as string
248- ) ;
239+ const blockSelection = editor
240+ . getApi ( BlockSelectionPlugin )
241+ . blockSelection . getNodes ( { sort : true } ) ;
242+
243+
244+ const selectedBlocks =
245+ blockSelection . length > 0
246+ ? blockSelection
247+ : editor . api . blocks ( { mode : 'highest' } ) ;
248+
249+ const ids = selectedBlocks . map ( ( block ) => block [ 0 ] . id as string ) ;
249250
250- if ( isSelected ) {
251- const previewTop = calculatePreviewTop ( editor , element ) ;
252- setMultiplePreviewTop ( previewTop ) ;
253- setIsMultiple ( true ) ;
251+
252+ if ( ids . length > 1 && ids . includes ( element . id as string ) ) {
253+ const previewTop = calculatePreviewTop ( editor , {
254+ blocks : selectedBlocks . map ( ( block ) => block [ 0 ] ) ,
255+ element,
256+ } ) ;
257+ setPreviewTop ( previewTop ) ;
254258 } else {
255- setIsMultiple ( false ) ;
259+ setPreviewTop ( 0 ) ;
256260 }
257261 } }
258- onMouseUp = { ( ) => {
259- multiplePreviewRef . current ?. replaceChildren ( ) ;
260- setIsMultiple ( false ) ;
261- } }
262262 role = "button"
263263 >
264264 < GripVertical className = "text-muted-foreground" />
@@ -292,12 +292,19 @@ const DropLine = React.memo(function DropLine({
292292 ) ;
293293} ) ;
294294
295- const createDragPreviewElements = ( editor : PlateEditor ) : HTMLElement [ ] => {
296- const blockSelectionApi = editor . getApi ( BlockSelectionPlugin ) . blockSelection ;
295+ const createDragPreviewElements = ( editor : PlateEditor , { currentBlock } : { currentBlock : TElement } ) : HTMLElement [ ] => {
296+ const blockSelection = editor . getApi ( BlockSelectionPlugin ) . blockSelection . getNodes ( { sort : true } ) ;
297+
298+ const selectionNodes = blockSelection . length > 0 ? blockSelection : editor . api . blocks ( { mode : 'highest' } ) ;
297299
298- const sortedNodes = blockSelectionApi . getNodes ( {
299- sort : true ,
300- } ) ;
300+ const includes = selectionNodes . some ( ( [ node ] ) => node . id === currentBlock . id ) ;
301+
302+ const sortedNodes = includes ? selectionNodes . map ( ( [ node ] ) => node ) : [ currentBlock ] ;
303+
304+ if ( blockSelection . length === 0 ) {
305+ editor . tf . blur ( ) ;
306+ editor . tf . collapse ( )
307+ }
301308
302309 const elements : HTMLElement [ ] = [ ] ;
303310 const ids : string [ ] = [ ] ;
@@ -335,7 +342,7 @@ const createDragPreviewElements = (editor: PlateEditor): HTMLElement[] => {
335342
336343 if ( lastDomNode ) {
337344 const lastDomNodeRect = editor . api
338- . toDOMNode ( lastDomNode [ 0 ] ) !
345+ . toDOMNode ( lastDomNode ) !
339346 . parentElement ! . getBoundingClientRect ( ) ;
340347
341348 const domNodeRect = domNode . parentElement ! . getBoundingClientRect ( ) ;
@@ -352,7 +359,7 @@ const createDragPreviewElements = (editor: PlateEditor): HTMLElement[] => {
352359 elements . push ( wrapper ) ;
353360 } ;
354361
355- sortedNodes . forEach ( ( [ node ] , index ) => resolveElement ( node , index ) ) ;
362+ sortedNodes . forEach ( ( node , index ) => resolveElement ( node , index ) ) ;
356363
357364 editor . setOption ( DndPlugin , 'draggingId' , ids ) ;
358365
@@ -361,15 +368,20 @@ const createDragPreviewElements = (editor: PlateEditor): HTMLElement[] => {
361368
362369const calculatePreviewTop = (
363370 editor : PlateEditor ,
364- element : TElement
371+ {
372+ blocks,
373+ element,
374+ } : {
375+ blocks : TElement [ ] ;
376+ element : TElement ;
377+ }
365378) : number => {
366- const blockSelectionApi = editor . getApi ( BlockSelectionPlugin ) . blockSelection ;
367379
368380 const child = editor . api . toDOMNode ( element ) ! ;
369381 const editable = editor . api . toDOMNode ( editor ) ! ;
370- const firstSelectedChild = editor . api . node ( blockSelectionApi . first ( ) ! [ 0 ] ) ! ;
382+ const firstSelectedChild = blocks [ 0 ]
371383
372- const firstDomNode = editor . api . toDOMNode ( firstSelectedChild [ 0 ] ) ! ;
384+ const firstDomNode = editor . api . toDOMNode ( firstSelectedChild ) ! ;
373385 // Get editor's top padding
374386 const editorPaddingTop = Number (
375387 window . getComputedStyle ( editable ) . paddingTop . replace ( 'px' , '' )
0 commit comments