11import { useCallback } from "react" ;
2- import { LogicalPosition } from "@tauri-apps/api/dpi" ;
3- import { Menu , MenuItem } from "@tauri-apps/api/menu" ;
4- import { getCurrentWindow } from "@tauri-apps/api/window" ;
2+ import type { MouseEvent as ReactMouseEvent } from "react" ;
53import type { QueuedMessage } from "../../../types" ;
4+ import {
5+ PopoverMenuItem ,
6+ PopoverSurface ,
7+ } from "../../design-system/components/popover/PopoverPrimitives" ;
8+ import { useMenuController } from "../../app/hooks/useMenuController" ;
69
710type ComposerQueueProps = {
811 queuedMessages : QueuedMessage [ ] ;
@@ -17,27 +20,6 @@ export function ComposerQueue({
1720 onEditQueued,
1821 onDeleteQueued,
1922} : ComposerQueueProps ) {
20- const handleQueueMenu = useCallback (
21- async ( event : React . MouseEvent , item : QueuedMessage ) => {
22- event . preventDefault ( ) ;
23- event . stopPropagation ( ) ;
24- const { clientX, clientY } = event ;
25- const editItem = await MenuItem . new ( {
26- text : "Edit" ,
27- action : ( ) => onEditQueued ?.( item ) ,
28- } ) ;
29- const deleteItem = await MenuItem . new ( {
30- text : "Delete" ,
31- action : ( ) => onDeleteQueued ?.( item . id ) ,
32- } ) ;
33- const menu = await Menu . new ( { items : [ editItem , deleteItem ] } ) ;
34- const window = getCurrentWindow ( ) ;
35- const position = new LogicalPosition ( clientX , clientY ) ;
36- await menu . popup ( position , window ) ;
37- } ,
38- [ onDeleteQueued , onEditQueued ] ,
39- ) ;
40-
4123 if ( queuedMessages . length === 0 ) {
4224 return null ;
4325 }
@@ -62,16 +44,63 @@ export function ComposerQueue({
6244 ? ` · ${ item . images . length } image${ item . images . length === 1 ? "" : "s" } `
6345 : "" }
6446 </ span >
65- < button
66- className = "composer-queue-menu"
67- onClick = { ( event ) => handleQueueMenu ( event , item ) }
68- aria-label = "Queue item menu"
69- >
70- ...
71- </ button >
47+ < QueueMenuButton
48+ item = { item }
49+ onEditQueued = { onEditQueued }
50+ onDeleteQueued = { onDeleteQueued }
51+ />
7252 </ div >
7353 ) ) }
7454 </ div >
7555 </ div >
7656 ) ;
7757}
58+
59+ type QueueMenuButtonProps = {
60+ item : QueuedMessage ;
61+ onEditQueued ?: ( item : QueuedMessage ) => void ;
62+ onDeleteQueued ?: ( id : string ) => void ;
63+ } ;
64+
65+ function QueueMenuButton ( { item, onEditQueued, onDeleteQueued } : QueueMenuButtonProps ) {
66+ const menu = useMenuController ( ) ;
67+ const handleToggleMenu = useCallback (
68+ ( event : ReactMouseEvent < HTMLButtonElement > ) => {
69+ event . preventDefault ( ) ;
70+ event . stopPropagation ( ) ;
71+ menu . toggle ( ) ;
72+ } ,
73+ [ menu ] ,
74+ ) ;
75+
76+ const handleEdit = useCallback ( ( ) => {
77+ menu . close ( ) ;
78+ onEditQueued ?.( item ) ;
79+ } , [ item , menu , onEditQueued ] ) ;
80+
81+ const handleDelete = useCallback ( ( ) => {
82+ menu . close ( ) ;
83+ onDeleteQueued ?.( item . id ) ;
84+ } , [ item . id , menu , onDeleteQueued ] ) ;
85+
86+ return (
87+ < div className = "composer-queue-menu-wrap" ref = { menu . containerRef } >
88+ < button
89+ type = "button"
90+ className = { `composer-queue-menu${ menu . isOpen ? " is-open" : "" } ` }
91+ onClick = { handleToggleMenu }
92+ aria-label = "Queue item menu"
93+ aria-haspopup = "menu"
94+ aria-expanded = { menu . isOpen }
95+ >
96+ ...
97+ </ button >
98+ { menu . isOpen && (
99+ < PopoverSurface className = "composer-queue-item-popover" role = "menu" >
100+ < PopoverMenuItem onClick = { handleEdit } > Edit</ PopoverMenuItem >
101+ < PopoverMenuItem onClick = { handleDelete } > Delete</ PopoverMenuItem >
102+ </ PopoverSurface >
103+ ) }
104+ </ div >
105+ ) ;
106+ }
0 commit comments