|
1 | 1 | import { useState, type ReactNode } from 'react'; |
2 | 2 | import { isDirty, type OpenTab } from '../editor/store'; |
| 3 | +import { ContextMenu } from './ContextMenu'; |
3 | 4 |
|
4 | 5 | interface EditorTabsProps { |
5 | 6 | tabs: OpenTab[]; |
6 | 7 | activeKey: string | null; |
7 | 8 | actions?: ReactNode; |
8 | 9 | onActivate: (key: string) => void; |
9 | 10 | onClose: (key: string) => void; |
| 11 | + onCloseOthers: (key: string) => void; |
| 12 | + onCloseAll: () => void; |
| 13 | + onReload: (key: string) => void; |
10 | 14 | onReorder: (from: number, to: number) => void; |
11 | 15 | } |
12 | 16 |
|
13 | | -export function EditorTabs({ tabs, activeKey, actions, onActivate, onClose, onReorder }: EditorTabsProps) { |
| 17 | +export function EditorTabs({ |
| 18 | + tabs, |
| 19 | + activeKey, |
| 20 | + actions, |
| 21 | + onActivate, |
| 22 | + onClose, |
| 23 | + onCloseOthers, |
| 24 | + onCloseAll, |
| 25 | + onReload, |
| 26 | + onReorder, |
| 27 | +}: EditorTabsProps) { |
14 | 28 | const [draggedIndex, setDraggedIndex] = useState<number | null>(null); |
15 | 29 | const [overIndex, setOverIndex] = useState<number | null>(null); |
| 30 | + const [menu, setMenu] = useState<{ key: string; x: number; y: number } | null>(null); |
16 | 31 |
|
17 | 32 | return ( |
18 | 33 | <div className="editor-tabs"> |
@@ -42,6 +57,10 @@ export function EditorTabs({ tabs, activeKey, actions, onActivate, onClose, onRe |
42 | 57 | }} |
43 | 58 | onClick={() => onActivate(tab.key)} |
44 | 59 | onKeyDown={event => event.key === 'Enter' && onActivate(tab.key)} |
| 60 | + onContextMenu={event => { |
| 61 | + event.preventDefault(); |
| 62 | + setMenu({ key: tab.key, x: event.clientX, y: event.clientY }); |
| 63 | + }} |
45 | 64 | className={[ |
46 | 65 | 'editor-tab', |
47 | 66 | tab.key === activeKey ? 'active' : '', |
@@ -69,6 +88,21 @@ export function EditorTabs({ tabs, activeKey, actions, onActivate, onClose, onRe |
69 | 88 | </div> |
70 | 89 |
|
71 | 90 | {actions !== undefined && <div className="tabs-actions">{actions}</div>} |
| 91 | + |
| 92 | + {menu !== null && ( |
| 93 | + <ContextMenu |
| 94 | + x={menu.x} |
| 95 | + y={menu.y} |
| 96 | + onDismiss={() => setMenu(null)} |
| 97 | + entries={[ |
| 98 | + { label: 'Reload from server', onSelect: () => onReload(menu.key) }, |
| 99 | + 'divider', |
| 100 | + { label: 'Close', onSelect: () => onClose(menu.key) }, |
| 101 | + { label: 'Close others', disabled: tabs.length < 2, onSelect: () => onCloseOthers(menu.key) }, |
| 102 | + { label: 'Close all', onSelect: onCloseAll }, |
| 103 | + ]} |
| 104 | + /> |
| 105 | + )} |
72 | 106 | </div> |
73 | 107 | ); |
74 | 108 | } |
0 commit comments