Skip to content

Commit 5d0a63c

Browse files
authored
Merge pull request #335 from anhgt26/patch-3
2 parents fcabd46 + 8b6d997 commit 5d0a63c

1 file changed

Lines changed: 145 additions & 136 deletions

File tree

src/components/Bubble/RichTextBubbleMenuDragHandle.tsx

Lines changed: 145 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useCallback, useEffect, useState } from 'react';
22

33
import DragHandle from '@tiptap/extension-drag-handle-react';
44
import { type NodeSelection } from '@tiptap/pm/state';
5+
import type { Editor } from '@tiptap/react';
56

67
import {
78
ActionButton,
@@ -83,12 +84,20 @@ export function RichTextBubbleMenuDragHandle() {
8384
.run();
8485
}
8586

86-
function handleNodeChange({ node, pos }: { node: Node | null; pos: number }) {
87-
if (node) {
88-
setCurrentNode(node);
87+
const handleNodeChange = useCallback((data: {
88+
node: Node | null;
89+
editor: Editor;
90+
pos: number
91+
}) => {
92+
if (data.node) {
93+
setCurrentNode(data.node);
8994
}
90-
setCurrentNodePos(pos);
91-
}
95+
setCurrentNodePos(data.pos);
96+
// Force update bubble menu position
97+
requestAnimationFrame(() => {
98+
data.editor.commands.focus();
99+
});
100+
}, []);
92101

93102
function handleAdd() {
94103
if (currentNodePos !== -1) {
@@ -164,166 +173,166 @@ export function RichTextBubbleMenuDragHandle() {
164173
handleMenuOpenChange(!menuOpen);
165174
}}
166175
/>
167-
</div>
168-
</DragHandle>
169-
170-
<DropdownMenu onOpenChange={handleMenuOpenChange}
171-
open={menuOpen}
172-
>
173-
<div className="richtext-relative richtext-flex richtext-flex-col">
174-
175-
<DropdownMenuTrigger className="richtext-absolute richtext-left-0 richtext-top-0 richtext-z-0 richtext-size-[28px]" />
176-
</div>
177176

178-
<DropdownMenuContent align="start"
179-
className="richtext-w-48"
180-
hideWhenDetached
181-
side="bottom"
182-
sideOffset={0}
183-
>
184-
<DropdownMenuItem
185-
className="richtext-flex richtext-gap-3 richtext-bg-opacity-10 hover:richtext-bg-red-400 hover:richtext-bg-opacity-20 focus:richtext-bg-red-400 focus:richtext-bg-opacity-30 focus:richtext-text-red-500 dark:hover:richtext-bg-opacity-20 dark:hover:richtext-text-red-500"
186-
onClick={deleteNode}
177+
<DropdownMenu onOpenChange={handleMenuOpenChange}
178+
open={menuOpen}
187179
>
188-
<IconComponent name="Trash2" />
180+
<div className="richtext-relative richtext-flex richtext-flex-col">
181+
<DropdownMenuTrigger className="richtext-absolute richtext-left-0 richtext-top-0 richtext-z-0 richtext-size-[28px]" />
182+
</div>
183+
184+
<DropdownMenuContent align="start"
185+
className="richtext-w-48"
186+
hideWhenDetached
187+
side="bottom"
188+
sideOffset={0}
189+
>
190+
<DropdownMenuItem
191+
className="richtext-flex richtext-gap-3 richtext-bg-opacity-10 hover:richtext-bg-red-400 hover:richtext-bg-opacity-20 focus:richtext-bg-red-400 focus:richtext-bg-opacity-30 focus:richtext-text-red-500 dark:hover:richtext-bg-opacity-20 dark:hover:richtext-text-red-500"
192+
onClick={deleteNode}
193+
>
194+
<IconComponent name="Trash2" />
189195

190-
<span>
196+
<span>
191197
{t('editor.remove')}
192-
</span>
193-
</DropdownMenuItem>
198+
</span>
199+
</DropdownMenuItem>
200+
201+
{hasClearExtension
202+
? (
203+
<DropdownMenuItem className="richtext-flex richtext-gap-3"
204+
onClick={resetTextFormatting}
205+
>
206+
<IconComponent name="PaintRoller" />
207+
208+
<span>
209+
{t('editor.clear.tooltip')}
210+
</span>
211+
</DropdownMenuItem>
212+
)
213+
: null}
194214

195-
{hasClearExtension
196-
? (
197215
<DropdownMenuItem className="richtext-flex richtext-gap-3"
198-
onClick={resetTextFormatting}
216+
onClick={copyNodeToClipboard}
199217
>
200-
<IconComponent name="PaintRoller" />
218+
<IconComponent name="Clipboard" />
201219

202220
<span>
203-
{t('editor.clear.tooltip')}
221+
{t('editor.copyToClipboard')}
204222
</span>
205223
</DropdownMenuItem>
206-
)
207-
: null}
208224

209-
<DropdownMenuItem className="richtext-flex richtext-gap-3"
210-
onClick={copyNodeToClipboard}
211-
>
212-
<IconComponent name="Clipboard" />
225+
<DropdownMenuItem className="richtext-flex richtext-gap-3"
226+
onClick={duplicateNode}
227+
>
228+
<IconComponent name="Copy" />
213229

214-
<span>
215-
{t('editor.copyToClipboard')}
216-
</span>
217-
</DropdownMenuItem>
230+
<span>
231+
{t('editor.copy')}
232+
</span>
233+
</DropdownMenuItem>
218234

219-
<DropdownMenuItem className="richtext-flex richtext-gap-3"
220-
onClick={duplicateNode}
221-
>
222-
<IconComponent name="Copy" />
235+
{hasTextAlignExtension || hasIndentExtension
236+
? (
237+
<DropdownMenuSeparator />
238+
)
239+
: null}
223240

224-
<span>
225-
{t('editor.copy')}
226-
</span>
227-
</DropdownMenuItem>
228-
229-
{hasTextAlignExtension || hasIndentExtension
230-
? (
231-
<DropdownMenuSeparator />
232-
)
233-
: null}
234-
235-
{hasTextAlignExtension
236-
? (
237-
<DropdownMenuSub>
238-
<DropdownMenuSubTrigger className="richtext-flex richtext-gap-3">
239-
<IconComponent name="AlignCenter" />
240-
241-
<span>
241+
{hasTextAlignExtension
242+
? (
243+
<DropdownMenuSub>
244+
<DropdownMenuSubTrigger className="richtext-flex richtext-gap-3">
245+
<IconComponent name="AlignCenter" />
246+
247+
<span>
242248
{t('editor.textalign.tooltip')}
243-
</span>
244-
</DropdownMenuSubTrigger>
249+
</span>
250+
</DropdownMenuSubTrigger>
245251

246-
<DropdownMenuPortal>
247-
<DropdownMenuSubContent>
248-
<DropdownMenuItem className="richtext-flex richtext-gap-3"
249-
onClick={() => setTextAlign('left')}
250-
>
251-
<IconComponent name="AlignLeft" />
252+
<DropdownMenuPortal>
253+
<DropdownMenuSubContent>
254+
<DropdownMenuItem className="richtext-flex richtext-gap-3"
255+
onClick={() => setTextAlign('left')}
256+
>
257+
<IconComponent name="AlignLeft" />
252258

253-
<span>
259+
<span>
254260
{t('editor.textalign.left.tooltip')}
255-
</span>
256-
</DropdownMenuItem>
261+
</span>
262+
</DropdownMenuItem>
257263

258-
<DropdownMenuItem className="richtext-flex richtext-gap-3"
259-
onClick={() => setTextAlign('center')}
260-
>
261-
<IconComponent name="AlignCenter" />
264+
<DropdownMenuItem className="richtext-flex richtext-gap-3"
265+
onClick={() => setTextAlign('center')}
266+
>
267+
<IconComponent name="AlignCenter" />
262268

263-
<span>
269+
<span>
264270
{t('editor.textalign.center.tooltip')}
265-
</span>
266-
</DropdownMenuItem>
271+
</span>
272+
</DropdownMenuItem>
267273

268-
<DropdownMenuItem className="richtext-flex richtext-gap-3"
269-
onClick={() => setTextAlign('right')}
270-
>
271-
<IconComponent name="AlignRight" />
274+
<DropdownMenuItem className="richtext-flex richtext-gap-3"
275+
onClick={() => setTextAlign('right')}
276+
>
277+
<IconComponent name="AlignRight" />
272278

273-
<span>
279+
<span>
274280
{t('editor.textalign.right.tooltip')}
275-
</span>
276-
</DropdownMenuItem>
277-
</DropdownMenuSubContent>
278-
</DropdownMenuPortal>
279-
</DropdownMenuSub>
280-
)
281-
: null}
282-
283-
{hasIndentExtension
284-
? (
285-
<DropdownMenuSub>
286-
<DropdownMenuSubTrigger className="richtext-flex richtext-gap-3">
287-
<IconComponent name="IndentIncrease" />
288-
289-
<span>
281+
</span>
282+
</DropdownMenuItem>
283+
</DropdownMenuSubContent>
284+
</DropdownMenuPortal>
285+
</DropdownMenuSub>
286+
)
287+
: null}
288+
289+
{hasIndentExtension
290+
? (
291+
<DropdownMenuSub>
292+
<DropdownMenuSubTrigger className="richtext-flex richtext-gap-3">
293+
<IconComponent name="IndentIncrease" />
294+
295+
<span>
290296
{t('editor.indent')}
291-
</span>
292-
</DropdownMenuSubTrigger>
293-
294-
<DropdownMenuPortal>
295-
<DropdownMenuSubContent>
296-
<DropdownMenuItem
297-
className="richtext-flex richtext-gap-3"
298-
disabled={currentNode?.attrs?.indent >= IndentProps.max}
299-
onClick={increaseIndent}
300-
>
301-
<IconComponent name="IndentIncrease" />
302-
303-
<span>
297+
</span>
298+
</DropdownMenuSubTrigger>
299+
300+
<DropdownMenuPortal>
301+
<DropdownMenuSubContent>
302+
<DropdownMenuItem
303+
className="richtext-flex richtext-gap-3"
304+
disabled={currentNode?.attrs?.indent >= IndentProps.max}
305+
onClick={increaseIndent}
306+
>
307+
<IconComponent name="IndentIncrease" />
308+
309+
<span>
304310
{t('editor.indent.tooltip')}
305-
</span>
306-
</DropdownMenuItem>
311+
</span>
312+
</DropdownMenuItem>
307313

308-
<DropdownMenuItem
309-
className="richtext-flex richtext-gap-3"
310-
disabled={currentNode?.attrs?.indent <= IndentProps.min}
311-
onClick={decreaseIndent}
312-
>
313-
<IconComponent name="IndentDecrease" />
314+
<DropdownMenuItem
315+
className="richtext-flex richtext-gap-3"
316+
disabled={currentNode?.attrs?.indent <= IndentProps.min}
317+
onClick={decreaseIndent}
318+
>
319+
<IconComponent name="IndentDecrease" />
314320

315-
<span>
321+
<span>
316322
{t('editor.outdent.tooltip')}
317-
</span>
318-
</DropdownMenuItem>
319-
</DropdownMenuSubContent>
320-
</DropdownMenuPortal>
321-
</DropdownMenuSub>
322-
)
323-
: null}
324-
325-
</DropdownMenuContent>
326-
</DropdownMenu>
323+
</span>
324+
</DropdownMenuItem>
325+
</DropdownMenuSubContent>
326+
</DropdownMenuPortal>
327+
</DropdownMenuSub>
328+
)
329+
: null}
330+
331+
</DropdownMenuContent>
332+
</DropdownMenu>
333+
</div>
334+
</DragHandle>
335+
327336
</>
328337
);
329338
}

0 commit comments

Comments
 (0)