flexlayout-react 0.5.18 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChangeLog.txt +27 -0
- package/README.md +126 -108
- package/declarations/Types.d.ts +8 -1
- package/declarations/model/IJsonModel.d.ts +3 -0
- package/declarations/model/Model.d.ts +2 -0
- package/declarations/view/Icons.d.ts +6 -0
- package/declarations/view/Layout.d.ts +8 -4
- package/declarations/view/MenuTabButton.d.ts +1 -0
- package/declarations/view/TabButtonStamp.d.ts +1 -0
- package/declarations/view/Utils.d.ts +1 -0
- package/dist/flexlayout.js +53 -17
- package/dist/flexlayout_min.js +1 -1
- package/lib/PopupMenu.js +22 -12
- package/lib/PopupMenu.js.map +1 -1
- package/lib/Types.js +7 -0
- package/lib/Types.js.map +1 -1
- package/lib/model/BorderNode.js +8 -7
- package/lib/model/BorderNode.js.map +1 -1
- package/lib/model/Model.js +15 -3
- package/lib/model/Model.js.map +1 -1
- package/lib/model/RowNode.js +19 -5
- package/lib/model/RowNode.js.map +1 -1
- package/lib/model/TabNode.js +6 -1
- package/lib/model/TabNode.js.map +1 -1
- package/lib/model/TabSetNode.js +8 -4
- package/lib/model/TabSetNode.js.map +1 -1
- package/lib/view/BorderButton.js +19 -38
- package/lib/view/BorderButton.js.map +1 -1
- package/lib/view/BorderTabSet.js +19 -8
- package/lib/view/BorderTabSet.js.map +1 -1
- package/lib/view/FloatingWindow.js +13 -5
- package/lib/view/FloatingWindow.js.map +1 -1
- package/lib/view/Icons.js +36 -0
- package/lib/view/Icons.js.map +1 -0
- package/lib/view/Layout.js +148 -71
- package/lib/view/Layout.js.map +1 -1
- package/lib/view/MenuTabButton.js +22 -0
- package/lib/view/MenuTabButton.js.map +1 -0
- package/lib/view/Splitter.js +3 -3
- package/lib/view/Splitter.js.map +1 -1
- package/lib/view/Tab.js +9 -6
- package/lib/view/Tab.js.map +1 -1
- package/lib/view/TabButton.js +20 -44
- package/lib/view/TabButton.js.map +1 -1
- package/lib/view/TabButtonStamp.js +22 -0
- package/lib/view/TabButtonStamp.js.map +1 -0
- package/lib/view/TabFloating.js +29 -15
- package/lib/view/TabFloating.js.map +1 -1
- package/lib/view/TabOverflowHook.js +1 -1
- package/lib/view/TabSet.js +40 -25
- package/lib/view/TabSet.js.map +1 -1
- package/lib/view/Utils.js +61 -0
- package/lib/view/Utils.js.map +1 -0
- package/package.json +11 -6
- package/src/I18nLabel.ts +1 -1
- package/src/PopupMenu.tsx +54 -15
- package/src/Types.ts +7 -0
- package/src/model/BorderNode.ts +8 -7
- package/src/model/IJsonModel.ts +3 -0
- package/src/model/Model.ts +19 -3
- package/src/model/RowNode.ts +8 -5
- package/src/model/TabNode.ts +6 -1
- package/src/model/TabSetNode.ts +8 -4
- package/src/view/BorderButton.tsx +38 -43
- package/src/view/BorderTabSet.tsx +34 -7
- package/src/view/FloatingWindow.tsx +14 -6
- package/src/view/Icons.tsx +36 -0
- package/src/view/Layout.tsx +179 -88
- package/src/view/Splitter.tsx +4 -1
- package/src/view/Tab.tsx +17 -6
- package/src/view/TabButton.tsx +42 -55
- package/src/view/TabButtonStamp.tsx +47 -0
- package/src/view/TabFloating.tsx +47 -23
- package/src/view/TabOverflowHook.tsx +1 -1
- package/src/view/TabSet.tsx +71 -22
- package/src/view/Utils.tsx +71 -0
- package/style/_base.scss +146 -92
- package/style/dark.css +157 -129
- package/style/dark.css.map +1 -1
- package/style/dark.scss +31 -21
- package/style/gray.css +157 -129
- package/style/gray.css.map +1 -1
- package/style/gray.scss +30 -23
- package/style/light.css +157 -129
- package/style/light.css.map +1 -1
- package/style/light.scss +30 -20
- package/images/close.png +0 -0
- package/images/maximize.png +0 -0
- package/images/more.png +0 -0
- package/images/more2.png +0 -0
- package/images/popout.png +0 -0
- package/images/restore.png +0 -0
package/src/view/TabButton.tsx
CHANGED
|
@@ -4,36 +4,47 @@ import Actions from "../model/Actions";
|
|
|
4
4
|
import TabNode from "../model/TabNode";
|
|
5
5
|
import TabSetNode from "../model/TabSetNode";
|
|
6
6
|
import Rect from "../Rect";
|
|
7
|
-
import { IIcons, ILayoutCallbacks
|
|
7
|
+
import { IIcons, ILayoutCallbacks } from "./Layout";
|
|
8
8
|
import { ICloseType } from "../model/ICloseType";
|
|
9
9
|
import { CLASSES } from "../Types";
|
|
10
|
+
import { getRenderStateEx, isAuxMouseEvent } from "./Utils";
|
|
10
11
|
|
|
11
12
|
/** @hidden @internal */
|
|
12
13
|
export interface ITabButtonProps {
|
|
13
14
|
layout: ILayoutCallbacks;
|
|
14
15
|
node: TabNode;
|
|
15
|
-
show: boolean;
|
|
16
16
|
selected: boolean;
|
|
17
17
|
height: number;
|
|
18
18
|
iconFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
19
19
|
titleFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
20
20
|
icons?: IIcons;
|
|
21
|
+
path: string;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/** @hidden @internal */
|
|
24
25
|
export const TabButton = (props: ITabButtonProps) => {
|
|
25
|
-
const { layout, node,
|
|
26
|
+
const { layout, node, selected, iconFactory, titleFactory, icons, path } = props;
|
|
26
27
|
const selfRef = React.useRef<HTMLDivElement | null>(null);
|
|
27
28
|
const contentRef = React.useRef<HTMLInputElement | null>(null);
|
|
28
29
|
const contentWidth = React.useRef<number>(0);
|
|
29
30
|
|
|
30
31
|
const onMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
layout.dragStart(event,
|
|
32
|
+
|
|
33
|
+
if (!isAuxMouseEvent(event) && !layout.getEditingTab()) {
|
|
34
|
+
layout.dragStart(event, undefined, node, node.isEnableDrag(), onClick, onDoubleClick);
|
|
34
35
|
}
|
|
35
36
|
};
|
|
36
37
|
|
|
38
|
+
const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
39
|
+
if (isAuxMouseEvent(event)) {
|
|
40
|
+
layout.auxMouseClick(node, event);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
45
|
+
layout.showContextMenu(node, event);
|
|
46
|
+
};
|
|
47
|
+
|
|
37
48
|
const onClick = () => {
|
|
38
49
|
layout.doAction(Actions.selectTab(node.getId()));
|
|
39
50
|
};
|
|
@@ -43,7 +54,7 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
43
54
|
layout.setEditingTab(node);
|
|
44
55
|
layout.getCurrentDocument()!.body.addEventListener("mousedown", onEndEdit);
|
|
45
56
|
layout.getCurrentDocument()!.body.addEventListener("touchstart", onEndEdit);
|
|
46
|
-
}
|
|
57
|
+
}
|
|
47
58
|
// else {
|
|
48
59
|
// const parentNode = node.getParent() as TabSetNode;
|
|
49
60
|
// if (parentNode.canMaximize()) {
|
|
@@ -98,7 +109,7 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
98
109
|
const layoutRect = layout.getDomRect();
|
|
99
110
|
const r = selfRef.current!.getBoundingClientRect();
|
|
100
111
|
node._setTabRect(new Rect(r.left - layoutRect.left, r.top - layoutRect.top, r.width, r.height));
|
|
101
|
-
contentWidth.current =
|
|
112
|
+
contentWidth.current = selfRef.current!.getBoundingClientRect().width;
|
|
102
113
|
};
|
|
103
114
|
|
|
104
115
|
const onTextBoxMouseDown = (event: React.MouseEvent<HTMLInputElement> | React.TouchEvent<HTMLInputElement>) => {
|
|
@@ -135,55 +146,24 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
135
146
|
classNames += " " + node.getClassName();
|
|
136
147
|
}
|
|
137
148
|
|
|
138
|
-
|
|
139
|
-
let titleContent: React.ReactNode = node.getName();
|
|
140
|
-
let name = node.getName();
|
|
141
|
-
|
|
142
|
-
function isTitleObject(obj: any): obj is ITitleObject {
|
|
143
|
-
return obj.titleContent !== undefined
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (titleFactory !== undefined) {
|
|
147
|
-
const titleObj = titleFactory(node);
|
|
148
|
-
if (titleObj !== undefined) {
|
|
149
|
-
if (typeof titleObj === "string") {
|
|
150
|
-
titleContent = titleObj as string;
|
|
151
|
-
name = titleObj as string;
|
|
152
|
-
} else if (isTitleObject(titleObj)) {
|
|
153
|
-
titleContent = titleObj.titleContent;
|
|
154
|
-
name = titleObj.name;
|
|
155
|
-
} else {
|
|
156
|
-
titleContent = titleObj;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (typeof leadingContent === undefined && typeof node.getIcon() !== undefined) {
|
|
162
|
-
leadingContent = <img src={node.getIcon()} alt="leadingContent" />;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let buttons: any[] = [];
|
|
166
|
-
|
|
167
|
-
// allow customization of leading contents (icon) and contents
|
|
168
|
-
const renderState = { leading: leadingContent, content: titleContent, name, buttons };
|
|
169
|
-
layout.customizeTab(node, renderState);
|
|
149
|
+
const renderState = getRenderStateEx(layout, node, iconFactory, titleFactory);
|
|
170
150
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
let content = (
|
|
174
|
-
<div ref={contentRef} className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_CONTENT)}>
|
|
151
|
+
let content = renderState.content ? (
|
|
152
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_CONTENT)}>
|
|
175
153
|
{renderState.content}
|
|
176
|
-
</div>
|
|
177
|
-
|
|
178
|
-
const leading =
|
|
154
|
+
</div>) : null;
|
|
155
|
+
|
|
156
|
+
const leading = renderState.leading ? (
|
|
157
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_LEADING)}>
|
|
158
|
+
{renderState.leading}
|
|
159
|
+
</div>) : null;
|
|
179
160
|
|
|
180
161
|
if (layout.getEditingTab() === node) {
|
|
181
|
-
const contentStyle = { width: contentWidth + "px" };
|
|
182
162
|
content = (
|
|
183
163
|
<input
|
|
184
|
-
style={contentStyle}
|
|
185
164
|
ref={contentRef}
|
|
186
165
|
className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TEXTBOX)}
|
|
166
|
+
data-layout-path={path + "/textbox"}
|
|
187
167
|
type="text"
|
|
188
168
|
autoFocus={true}
|
|
189
169
|
defaultValue={node.getName()}
|
|
@@ -196,8 +176,14 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
196
176
|
|
|
197
177
|
if (node.isEnableClose()) {
|
|
198
178
|
const closeTitle = layout.i18nName(I18nLabel.Close_Tab);
|
|
199
|
-
buttons.push(
|
|
200
|
-
<div
|
|
179
|
+
renderState.buttons.push(
|
|
180
|
+
<div
|
|
181
|
+
key="close"
|
|
182
|
+
data-layout-path={path + "/button/close"}
|
|
183
|
+
title={closeTitle}
|
|
184
|
+
className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TRAILING)}
|
|
185
|
+
onMouseDown={onCloseMouseDown} onClick={onClose}
|
|
186
|
+
onTouchStart={onCloseMouseDown}>
|
|
201
187
|
{icons?.close}
|
|
202
188
|
</div>
|
|
203
189
|
);
|
|
@@ -206,17 +192,18 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
206
192
|
return (
|
|
207
193
|
<div
|
|
208
194
|
ref={selfRef}
|
|
209
|
-
|
|
210
|
-
visibility: show ? "visible" : "hidden",
|
|
211
|
-
}}
|
|
195
|
+
data-layout-path={path}
|
|
212
196
|
className={classNames}
|
|
213
197
|
onMouseDown={onMouseDown}
|
|
198
|
+
onClick={onAuxMouseClick}
|
|
199
|
+
onAuxClick={onAuxMouseClick}
|
|
200
|
+
onContextMenu={onContextMenu}
|
|
214
201
|
onTouchStart={onMouseDown}
|
|
215
202
|
title={node.getHelpText()}
|
|
216
203
|
>
|
|
217
204
|
{leading}
|
|
218
205
|
{content}
|
|
219
|
-
{buttons}
|
|
206
|
+
{renderState.buttons}
|
|
220
207
|
</div>
|
|
221
208
|
);
|
|
222
209
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import TabNode from "../model/TabNode";
|
|
3
|
+
import { ILayoutCallbacks } from "./Layout";
|
|
4
|
+
import { CLASSES } from "../Types";
|
|
5
|
+
import { getRenderStateEx } from "./Utils";
|
|
6
|
+
|
|
7
|
+
/** @hidden @internal */
|
|
8
|
+
export interface ITabButtonStampProps {
|
|
9
|
+
node: TabNode;
|
|
10
|
+
layout: ILayoutCallbacks;
|
|
11
|
+
iconFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
12
|
+
titleFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** @hidden @internal */
|
|
16
|
+
export const TabButtonStamp = (props: ITabButtonStampProps) => {
|
|
17
|
+
const { layout, node, iconFactory, titleFactory } = props;
|
|
18
|
+
const selfRef = React.useRef<HTMLDivElement | null>(null);
|
|
19
|
+
|
|
20
|
+
const cm = layout.getClassName;
|
|
21
|
+
|
|
22
|
+
let classNames = cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_STAMP);
|
|
23
|
+
|
|
24
|
+
const renderState = getRenderStateEx(layout, node, iconFactory, titleFactory);
|
|
25
|
+
|
|
26
|
+
let content = renderState.content ? (
|
|
27
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_CONTENT)}>
|
|
28
|
+
{renderState.content}
|
|
29
|
+
</div>)
|
|
30
|
+
: node._getNameForOverflowMenu();
|
|
31
|
+
|
|
32
|
+
const leading = renderState.leading ? (
|
|
33
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_LEADING)}>
|
|
34
|
+
{renderState.leading}
|
|
35
|
+
</div>) : null;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
ref={selfRef}
|
|
40
|
+
className={classNames}
|
|
41
|
+
title={node.getHelpText()}
|
|
42
|
+
>
|
|
43
|
+
{leading}
|
|
44
|
+
{content}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
};
|
package/src/view/TabFloating.tsx
CHANGED
|
@@ -5,17 +5,29 @@ import TabSetNode from "../model/TabSetNode";
|
|
|
5
5
|
import { CLASSES } from "../Types";
|
|
6
6
|
import { ILayoutCallbacks } from "./Layout";
|
|
7
7
|
import { I18nLabel } from "../I18nLabel";
|
|
8
|
+
import { hideElement } from "./Utils";
|
|
8
9
|
|
|
9
10
|
/** @hidden @internal */
|
|
10
11
|
export interface ITabFloatingProps {
|
|
11
12
|
layout: ILayoutCallbacks;
|
|
12
13
|
selected: boolean;
|
|
13
14
|
node: TabNode;
|
|
15
|
+
path: string;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/** @hidden @internal */
|
|
17
19
|
export const TabFloating = (props: ITabFloatingProps) => {
|
|
18
|
-
const { layout, selected, node } = props;
|
|
20
|
+
const { layout, selected, node, path } = props;
|
|
21
|
+
|
|
22
|
+
const showPopout = () => {
|
|
23
|
+
if (node.getWindow()) {
|
|
24
|
+
node.getWindow()!.focus();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const dockPopout = () => {
|
|
29
|
+
layout.doAction(Actions.unFloatTab(node.getId()));
|
|
30
|
+
}
|
|
19
31
|
|
|
20
32
|
const onMouseDown = () => {
|
|
21
33
|
const parent = node.getParent() as TabSetNode;
|
|
@@ -28,41 +40,53 @@ export const TabFloating = (props: ITabFloatingProps) => {
|
|
|
28
40
|
|
|
29
41
|
const onClickFocus = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
|
30
42
|
event.preventDefault();
|
|
31
|
-
|
|
32
|
-
node.getWindow()!.focus();
|
|
33
|
-
}
|
|
43
|
+
showPopout();
|
|
34
44
|
};
|
|
35
45
|
|
|
36
46
|
const onClickDock = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
|
37
47
|
event.preventDefault();
|
|
38
|
-
|
|
48
|
+
dockPopout();
|
|
39
49
|
};
|
|
40
50
|
|
|
41
51
|
const cm = layout.getClassName;
|
|
42
52
|
|
|
43
|
-
const style: Record<string, any> = node._styleWithPosition(
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
const style: Record<string, any> = node._styleWithPosition();
|
|
54
|
+
if (!selected) {
|
|
55
|
+
hideElement(style, node.getModel().isUseVisibility());
|
|
56
|
+
}
|
|
46
57
|
|
|
47
58
|
const message = layout.i18nName(I18nLabel.Floating_Window_Message);
|
|
48
59
|
const showMessage = layout.i18nName(I18nLabel.Floating_Window_Show_Window);
|
|
49
60
|
const dockMessage = layout.i18nName(I18nLabel.Floating_Window_Dock_Window);
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const customRenderCallback = layout.getOnRenderFloatingTabPlaceholder();
|
|
63
|
+
if (customRenderCallback) {
|
|
64
|
+
return (
|
|
65
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
|
|
66
|
+
{customRenderCallback(dockPopout, showPopout)}
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
} else {
|
|
70
|
+
return (
|
|
71
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)}
|
|
72
|
+
data-layout-path={path}
|
|
73
|
+
onMouseDown={onMouseDown}
|
|
74
|
+
onTouchStart={onMouseDown}
|
|
75
|
+
style={style}>
|
|
76
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING_INNER)}>
|
|
77
|
+
<div>{message}</div>
|
|
78
|
+
<div>
|
|
79
|
+
<a href="#" onClick={onClickFocus}>
|
|
80
|
+
{showMessage}
|
|
81
|
+
</a>
|
|
82
|
+
</div>
|
|
83
|
+
<div>
|
|
84
|
+
<a href="#" onClick={onClickDock}>
|
|
85
|
+
{dockMessage}
|
|
86
|
+
</a>
|
|
87
|
+
</div>
|
|
64
88
|
</div>
|
|
65
89
|
</div>
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
);
|
|
91
|
+
}
|
|
68
92
|
};
|
|
@@ -92,7 +92,7 @@ export const useTabOverflow = (
|
|
|
92
92
|
return; // nothing to do all tabs are shown in available space
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
endPos -= hiddenTabs.length > 0 ? (orientation === Orientation.HORZ ?
|
|
95
|
+
endPos -= hiddenTabs.length > 0 ? (orientation === Orientation.HORZ ? 16 : 0) : 45; // will need hidden tabs
|
|
96
96
|
|
|
97
97
|
let shiftPos = 0;
|
|
98
98
|
|
package/src/view/TabSet.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { TabButton } from "./TabButton";
|
|
|
9
9
|
import { useTabOverflow } from "./TabOverflowHook";
|
|
10
10
|
import Orientation from "../Orientation";
|
|
11
11
|
import { CLASSES } from "../Types";
|
|
12
|
+
import { hideElement, isAuxMouseEvent } from "./Utils";
|
|
12
13
|
|
|
13
14
|
/** @hidden @internal */
|
|
14
15
|
export interface ITabSetProps {
|
|
@@ -17,12 +18,13 @@ export interface ITabSetProps {
|
|
|
17
18
|
iconFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
18
19
|
titleFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
19
20
|
icons?: IIcons;
|
|
20
|
-
editingTab?: TabNode;
|
|
21
|
+
editingTab?: TabNode;
|
|
22
|
+
path?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/** @hidden @internal */
|
|
24
26
|
export const TabSet = (props: ITabSetProps) => {
|
|
25
|
-
const { node, layout, iconFactory, titleFactory, icons } = props;
|
|
27
|
+
const { node, layout, iconFactory, titleFactory, icons, path } = props;
|
|
26
28
|
|
|
27
29
|
const toolbarRef = React.useRef<HTMLDivElement | null>(null);
|
|
28
30
|
const overflowbuttonRef = React.useRef<HTMLButtonElement | null>(null);
|
|
@@ -31,9 +33,17 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
31
33
|
|
|
32
34
|
const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel, tabsTruncated } = useTabOverflow(node, Orientation.HORZ, toolbarRef, stickyButtonsRef);
|
|
33
35
|
|
|
34
|
-
const onOverflowClick = () => {
|
|
36
|
+
const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
35
37
|
const element = overflowbuttonRef.current!;
|
|
36
|
-
showPopup(
|
|
38
|
+
showPopup(
|
|
39
|
+
element,
|
|
40
|
+
hiddenTabs,
|
|
41
|
+
onOverflowItemSelect,
|
|
42
|
+
layout,
|
|
43
|
+
iconFactory,
|
|
44
|
+
titleFactory,
|
|
45
|
+
);
|
|
46
|
+
event.stopPropagation();
|
|
37
47
|
};
|
|
38
48
|
|
|
39
49
|
const onOverflowItemSelect = (item: { node: TabNode; index: number }) => {
|
|
@@ -42,37 +52,52 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
42
52
|
};
|
|
43
53
|
|
|
44
54
|
const onMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
name
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
if (!isAuxMouseEvent(event)) {
|
|
56
|
+
let name = node.getName();
|
|
57
|
+
if (name === undefined) {
|
|
58
|
+
name = "";
|
|
59
|
+
} else {
|
|
60
|
+
name = ": " + name;
|
|
61
|
+
}
|
|
62
|
+
layout.doAction(Actions.setActiveTabset(node.getId()));
|
|
63
|
+
if (!layout.getEditingTab()) {
|
|
64
|
+
const message = layout.i18nName(I18nLabel.Move_Tabset, name);
|
|
65
|
+
layout.dragStart(event, message, node, node.isEnableDrag(), (event2: Event) => undefined, onDoubleClick);
|
|
66
|
+
}
|
|
50
67
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
71
|
+
if (isAuxMouseEvent(event)) {
|
|
72
|
+
layout.auxMouseClick(node, event);
|
|
55
73
|
}
|
|
56
74
|
};
|
|
57
75
|
|
|
76
|
+
const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
|
77
|
+
layout.showContextMenu(node, event);
|
|
78
|
+
};
|
|
79
|
+
|
|
58
80
|
const onInterceptMouseDown = (event: React.MouseEvent | React.TouchEvent) => {
|
|
59
81
|
event.stopPropagation();
|
|
60
82
|
};
|
|
61
83
|
|
|
62
|
-
const onMaximizeToggle = () => {
|
|
84
|
+
const onMaximizeToggle = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
63
85
|
if (node.canMaximize()) {
|
|
64
86
|
layout.maximize(node);
|
|
65
87
|
}
|
|
88
|
+
event.stopPropagation();
|
|
66
89
|
};
|
|
67
90
|
|
|
68
|
-
const onClose = () => {
|
|
91
|
+
const onClose = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
69
92
|
layout.doAction(Actions.deleteTabset(node.getId()));
|
|
93
|
+
event.stopPropagation();
|
|
70
94
|
};
|
|
71
95
|
|
|
72
|
-
const onFloatTab = () => {
|
|
96
|
+
const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
73
97
|
if (selectedTabNode !== undefined) {
|
|
74
98
|
layout.doAction(Actions.floatTab(selectedTabNode.getId()));
|
|
75
99
|
}
|
|
100
|
+
event.stopPropagation();
|
|
76
101
|
};
|
|
77
102
|
|
|
78
103
|
const onDoubleClick = (event: Event) => {
|
|
@@ -93,7 +118,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
93
118
|
let style = node._styleWithPosition();
|
|
94
119
|
|
|
95
120
|
if (node.getModel().getMaximizedTabset() !== undefined && !node.isMaximized()) {
|
|
96
|
-
style.
|
|
121
|
+
hideElement(style, node.getModel().isUseVisibility())
|
|
97
122
|
}
|
|
98
123
|
|
|
99
124
|
const tabs = [];
|
|
@@ -105,9 +130,9 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
105
130
|
<TabButton
|
|
106
131
|
layout={layout}
|
|
107
132
|
node={child}
|
|
133
|
+
path={path + "/tb" + i}
|
|
108
134
|
key={child.getId()}
|
|
109
135
|
selected={isSelected}
|
|
110
|
-
show={true}
|
|
111
136
|
height={node.getTabStripHeight()}
|
|
112
137
|
iconFactory={iconFactory}
|
|
113
138
|
titleFactory={titleFactory}
|
|
@@ -153,8 +178,10 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
153
178
|
buttons.push(
|
|
154
179
|
<button
|
|
155
180
|
key="overflowbutton"
|
|
181
|
+
data-layout-path={path + "/button/overflow"}
|
|
182
|
+
|
|
156
183
|
ref={overflowbuttonRef}
|
|
157
|
-
className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
|
|
184
|
+
className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
|
|
158
185
|
title={overflowTitle}
|
|
159
186
|
onClick={onOverflowClick}
|
|
160
187
|
onMouseDown={onInterceptMouseDown}
|
|
@@ -171,6 +198,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
171
198
|
buttons.push(
|
|
172
199
|
<button
|
|
173
200
|
key="float"
|
|
201
|
+
data-layout-path={path + "/button/float"}
|
|
174
202
|
title={floatTitle}
|
|
175
203
|
className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_FLOAT)}
|
|
176
204
|
onClick={onFloatTab}
|
|
@@ -188,6 +216,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
188
216
|
btns.push(
|
|
189
217
|
<button
|
|
190
218
|
key="max"
|
|
219
|
+
data-layout-path={path + "/button/max"}
|
|
191
220
|
title={node.isMaximized() ? minTitle : maxTitle}
|
|
192
221
|
className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_ + (node.isMaximized() ? "max" : "min"))}
|
|
193
222
|
onClick={onMaximizeToggle}
|
|
@@ -205,6 +234,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
205
234
|
btns.push(
|
|
206
235
|
<button
|
|
207
236
|
key="close"
|
|
237
|
+
data-layout-path={path + "/button/close"}
|
|
208
238
|
title={title}
|
|
209
239
|
className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE)}
|
|
210
240
|
onClick={onClose}
|
|
@@ -269,7 +299,13 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
269
299
|
}
|
|
270
300
|
|
|
271
301
|
header = (
|
|
272
|
-
<div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }}
|
|
302
|
+
<div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }}
|
|
303
|
+
data-layout-path={path + "/header"}
|
|
304
|
+
onMouseDown={onMouseDown}
|
|
305
|
+
onContextMenu={onContextMenu}
|
|
306
|
+
onClick={onAuxMouseClick}
|
|
307
|
+
onAuxClick={onAuxMouseClick}
|
|
308
|
+
onTouchStart={onMouseDown}>
|
|
273
309
|
<div className={cm(CLASSES.FLEXLAYOUT__TABSET_HEADER_CONTENT)}>{headerContent}</div>
|
|
274
310
|
{headerToolbar}
|
|
275
311
|
</div>
|
|
@@ -284,7 +320,13 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
284
320
|
tabStripStyle["bottom"] = "0px";
|
|
285
321
|
}
|
|
286
322
|
tabStrip = (
|
|
287
|
-
<div className={tabStripClasses} style={tabStripStyle}
|
|
323
|
+
<div className={tabStripClasses} style={tabStripStyle}
|
|
324
|
+
data-layout-path={path + "/tabstrip"}
|
|
325
|
+
onMouseDown={onMouseDown}
|
|
326
|
+
onContextMenu={onContextMenu}
|
|
327
|
+
onClick={onAuxMouseClick}
|
|
328
|
+
onAuxClick={onAuxMouseClick}
|
|
329
|
+
onTouchStart={onMouseDown}>
|
|
288
330
|
<div ref={tabbarInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
|
|
289
331
|
<div
|
|
290
332
|
style={{ left: position }}
|
|
@@ -300,9 +342,16 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
300
342
|
style = layout.styleFont(style);
|
|
301
343
|
|
|
302
344
|
return (
|
|
303
|
-
<div ref={selfRef}
|
|
345
|
+
<div ref={selfRef}
|
|
346
|
+
dir="ltr"
|
|
347
|
+
data-layout-path={path}
|
|
348
|
+
style={style}
|
|
349
|
+
className={cm(CLASSES.FLEXLAYOUT__TABSET)}
|
|
350
|
+
onWheel={onMouseWheel}>
|
|
304
351
|
{header}
|
|
305
352
|
{tabStrip}
|
|
306
353
|
</div>
|
|
307
354
|
);
|
|
308
355
|
};
|
|
356
|
+
|
|
357
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import TabNode from "../model/TabNode";
|
|
3
|
+
import { ILayoutCallbacks, ITitleObject } from "./Layout";
|
|
4
|
+
|
|
5
|
+
/** @hidden @internal */
|
|
6
|
+
export function getRenderStateEx (
|
|
7
|
+
layout: ILayoutCallbacks,
|
|
8
|
+
node: TabNode,
|
|
9
|
+
iconFactory?: (node: TabNode) => React.ReactNode | undefined,
|
|
10
|
+
titleFactory?: (node: TabNode) => React.ReactNode | undefined
|
|
11
|
+
) {
|
|
12
|
+
let leadingContent = iconFactory ? iconFactory(node) : undefined;
|
|
13
|
+
let titleContent: React.ReactNode = node.getName();
|
|
14
|
+
let name = node.getName();
|
|
15
|
+
|
|
16
|
+
function isTitleObject(obj: any): obj is ITitleObject {
|
|
17
|
+
return obj.titleContent !== undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (titleFactory !== undefined) {
|
|
21
|
+
const titleObj = titleFactory(node);
|
|
22
|
+
if (titleObj !== undefined) {
|
|
23
|
+
if (typeof titleObj === "string") {
|
|
24
|
+
titleContent = titleObj as string;
|
|
25
|
+
name = titleObj as string;
|
|
26
|
+
} else if (isTitleObject(titleObj)) {
|
|
27
|
+
titleContent = titleObj.titleContent;
|
|
28
|
+
name = titleObj.name;
|
|
29
|
+
} else {
|
|
30
|
+
titleContent = titleObj;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (leadingContent === undefined && node.getIcon() !== undefined) {
|
|
36
|
+
leadingContent = <img style={{width:"1em", height:"1em"}} src={node.getIcon()} alt="leadingContent" />;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let buttons: any[] = [];
|
|
40
|
+
|
|
41
|
+
// allow customization of leading contents (icon) and contents
|
|
42
|
+
const renderState = { leading: leadingContent, content: titleContent, name, buttons };
|
|
43
|
+
layout.customizeTab(node, renderState);
|
|
44
|
+
|
|
45
|
+
node._setRenderedName(renderState.name);
|
|
46
|
+
|
|
47
|
+
return renderState;
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @hidden @internal */
|
|
52
|
+
export function hideElement(style: Record<string, any>, useVisibility: ConstrainBoolean ) {
|
|
53
|
+
if (useVisibility) {
|
|
54
|
+
style.visibility = "hidden";
|
|
55
|
+
} else {
|
|
56
|
+
style.display = "none";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/** @hidden @internal */
|
|
62
|
+
export function isAuxMouseEvent(event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) {
|
|
63
|
+
let auxEvent = false;
|
|
64
|
+
if (event.nativeEvent instanceof MouseEvent) {
|
|
65
|
+
if (event.nativeEvent.button !== 0 || event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) {
|
|
66
|
+
auxEvent = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return auxEvent;
|
|
70
|
+
}
|
|
71
|
+
|