Skip to content

Commit d45138c

Browse files
committed
feat: support move editor tabs over the tabbar
1 parent 795a5b4 commit d45138c

2 files changed

Lines changed: 74 additions & 39 deletions

File tree

packages/editor/src/browser/editor.module.less

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
flex-grow: 1;
9292
width: 100%;
9393
position: relative;
94+
background-color: var(--editorGroupHeader-tabsBackground);
9495
&::before {
9596
position: absolute;
9697
content: '';
@@ -111,11 +112,13 @@
111112
z-index: 10;
112113
background-color: var(--tab-border);
113114
}
115+
&.kt_on_drag_over {
116+
background-color: var(--editorGroup-dropBackground);
117+
}
114118
}
115119

116120
.kt_editor_tabs_scroll {
117121
overflow-y: hidden;
118-
background: var(--editorGroupHeader-tabsBackground);
119122
:global(.loading_indicator) {
120123
width: 16px;
121124
height: 22px;

packages/editor/src/browser/tab.view.tsx

Lines changed: 70 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import 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

416
import { Scrollbars } from '@opensumi/ide-components';
517
import {
@@ -38,7 +50,8 @@ export interface ITabsProps {
3850

3951
export 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

414446
export 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

Comments
 (0)