11import classnames from 'classnames' ;
2- import React , { useEffect , useState , useCallback , useRef , useContext , useMemo , forwardRef } from 'react' ;
2+ import React , {
3+ useEffect ,
4+ useState ,
5+ useCallback ,
6+ useRef ,
7+ useContext ,
8+ useMemo ,
9+ forwardRef ,
10+ DragEvent ,
11+ HTMLAttributes ,
12+ Ref ,
13+ MouseEvent ,
14+ } from 'react' ;
315
416import { Scrollbars } from '@opensumi/ide-components' ;
517import {
@@ -38,7 +50,8 @@ export interface ITabsProps {
3850
3951export const Tabs = ( { group } : ITabsProps ) => {
4052 const tabContainer = useRef < HTMLDivElement | null > ( ) ;
41- const contentRef = useRef < HTMLDivElement > ( ) ;
53+ const tabWrapperRef = useRef < HTMLDivElement | null > ( ) ;
54+ const contentRef = useRef < HTMLDivElement | null > ( ) ;
4255 const editorActionUpdateTimer = useRef < any > ( null ) ;
4356 const editorActionRef = useRef < typeof EditorActions > ( null ) ;
4457 const resourceService = useInjectable ( ResourceService ) as ResourceService ;
@@ -94,7 +107,7 @@ export const Tabs = ({ group }: ITabsProps) => {
94107 } , [ group ] ) ;
95108
96109 const onDrop = useCallback (
97- ( e : React . DragEvent , index : number , target ?: IResource ) => {
110+ ( e : DragEvent , index : number , target ?: IResource ) => {
98111 if ( e . dataTransfer . getData ( 'uri' ) ) {
99112 const uri = new URI ( e . dataTransfer . getData ( 'uri' ) ) ;
100113 let sourceGroup : EditorGroup | undefined ;
@@ -180,7 +193,7 @@ export const Tabs = ({ group }: ITabsProps) => {
180193 }
181194 } , [ wrapMode ] ) ;
182195
183- const layoutLastInRow = React . useCallback ( ( ) => {
196+ const layoutLastInRow = useCallback ( ( ) => {
184197 if ( contentRef . current && wrapMode ) {
185198 const newMap : Map < number , boolean > = new Map ( ) ;
186199
@@ -259,37 +272,49 @@ export const Tabs = ({ group }: ITabsProps) => {
259272 } ;
260273 } , [ group ] ) ;
261274
275+ const handleWrapperDragOver = useCallback (
276+ ( e : DragEvent ) => {
277+ e . preventDefault ( ) ;
278+ e . stopPropagation ( ) ;
279+ if ( tabWrapperRef . current ) {
280+ tabWrapperRef . current . classList . add ( styles . kt_on_drag_over ) ;
281+ }
282+ } ,
283+ [ tabWrapperRef . current ] ,
284+ ) ;
285+
286+ const handleWrapperDragLeave = useCallback (
287+ ( e : DragEvent ) => {
288+ if ( tabWrapperRef . current ) {
289+ tabWrapperRef . current . classList . remove ( styles . kt_on_drag_over ) ;
290+ }
291+ } ,
292+ [ tabWrapperRef . current ] ,
293+ ) ;
294+
295+ const handleWrapperDrag = useCallback (
296+ ( e : DragEvent ) => {
297+ if ( tabWrapperRef . current ) {
298+ tabWrapperRef . current . classList . remove ( styles . kt_on_drag_over ) ;
299+ }
300+ if ( onDrop ) {
301+ onDrop ( e , - 1 ) ;
302+ }
303+ } ,
304+ [ onDrop , tabWrapperRef . current ] ,
305+ ) ;
306+
307+ const handleEmptyDBClick = useCallback (
308+ ( e : MouseEvent ) => {
309+ if ( e . target === e . currentTarget ) {
310+ editorService . createUntitledResource ( ) ;
311+ }
312+ } ,
313+ [ editorService ] ,
314+ ) ;
315+
262316 const renderTabContent = ( ) => (
263- < div
264- className = { styles . kt_editor_tabs_content }
265- ref = { contentRef as any }
266- onDragLeave = { ( ) => {
267- if ( contentRef . current ) {
268- contentRef . current . classList . remove ( styles . kt_on_drag_over ) ;
269- }
270- } }
271- onDragOver = { ( e ) => {
272- e . preventDefault ( ) ;
273- e . stopPropagation ( ) ;
274- if ( contentRef . current ) {
275- contentRef . current . classList . add ( styles . kt_on_drag_over ) ;
276- }
277- } }
278- onDrop = { ( e ) => {
279- if ( contentRef . current ) {
280- contentRef . current . classList . remove ( styles . kt_on_drag_over ) ;
281- }
282- if ( onDrop ) {
283- onDrop ( e , - 1 ) ;
284- }
285- } }
286- onDoubleClick = { ( e ) => {
287- // 只处理 tab 组空余的地方
288- if ( e . target === e . currentTarget ) {
289- editorService . createUntitledResource ( ) ;
290- }
291- } }
292- >
317+ < div className = { styles . kt_editor_tabs_content } ref = { contentRef as any } >
293318 { group . resources . map ( ( resource , i ) => {
294319 let ref : HTMLDivElement | null ;
295320 const decoration = resourceService . getResourceDecoration ( resource . uri ) ;
@@ -325,14 +350,14 @@ export const Tabs = ({ group }: ITabsProps) => {
325350 group . open ( resource . uri , { focus : true } ) ;
326351 }
327352 } }
353+ data-uri = { resource . uri . toString ( ) }
328354 onDragOver = { ( e ) => {
329355 e . preventDefault ( ) ;
330356 e . stopPropagation ( ) ;
331357 if ( ref ) {
332358 ref . classList . add ( styles . kt_on_drag_over ) ;
333359 }
334360 } }
335- data-uri = { resource . uri . toString ( ) }
336361 onDragLeave = { ( e ) => {
337362 if ( ref ) {
338363 ref . classList . remove ( styles . kt_on_drag_over ) ;
@@ -386,7 +411,14 @@ export const Tabs = ({ group }: ITabsProps) => {
386411
387412 return (
388413 < div id = { VIEW_CONTAINERS . EDITOR_TABS } className = { styles . kt_editor_tabs } >
389- < div className = { styles . kt_editor_tabs_scroll_wrapper } >
414+ < div
415+ className = { styles . kt_editor_tabs_scroll_wrapper }
416+ ref = { tabWrapperRef as any }
417+ onDragOver = { handleWrapperDragOver }
418+ onDragLeave = { handleWrapperDragLeave }
419+ onDrop = { handleWrapperDrag }
420+ onDoubleClick = { handleEmptyDBClick }
421+ >
390422 { ! wrapMode ? (
391423 < Scrollbars
392424 thumbSize = { 5 }
@@ -409,10 +441,10 @@ export interface IEditorActionsBaseProps {
409441 className ?: string ;
410442}
411443
412- export type IEditorActionsProps = IEditorActionsBaseProps & React . HTMLAttributes < HTMLDivElement > ;
444+ export type IEditorActionsProps = IEditorActionsBaseProps & HTMLAttributes < HTMLDivElement > ;
413445
414446export const EditorActions = forwardRef < HTMLDivElement , IEditorActionsProps > (
415- ( props : IEditorActionsProps , ref : React . Ref < typeof EditorActions > ) => {
447+ ( props : IEditorActionsProps , ref : Ref < typeof EditorActions > ) => {
416448 const { group, className } = props ;
417449
418450 const acquireArgs = useCallback (
0 commit comments