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.
Files changed (92) hide show
  1. package/ChangeLog.txt +27 -0
  2. package/README.md +126 -108
  3. package/declarations/Types.d.ts +8 -1
  4. package/declarations/model/IJsonModel.d.ts +3 -0
  5. package/declarations/model/Model.d.ts +2 -0
  6. package/declarations/view/Icons.d.ts +6 -0
  7. package/declarations/view/Layout.d.ts +8 -4
  8. package/declarations/view/MenuTabButton.d.ts +1 -0
  9. package/declarations/view/TabButtonStamp.d.ts +1 -0
  10. package/declarations/view/Utils.d.ts +1 -0
  11. package/dist/flexlayout.js +53 -17
  12. package/dist/flexlayout_min.js +1 -1
  13. package/lib/PopupMenu.js +22 -12
  14. package/lib/PopupMenu.js.map +1 -1
  15. package/lib/Types.js +7 -0
  16. package/lib/Types.js.map +1 -1
  17. package/lib/model/BorderNode.js +8 -7
  18. package/lib/model/BorderNode.js.map +1 -1
  19. package/lib/model/Model.js +15 -3
  20. package/lib/model/Model.js.map +1 -1
  21. package/lib/model/RowNode.js +19 -5
  22. package/lib/model/RowNode.js.map +1 -1
  23. package/lib/model/TabNode.js +6 -1
  24. package/lib/model/TabNode.js.map +1 -1
  25. package/lib/model/TabSetNode.js +8 -4
  26. package/lib/model/TabSetNode.js.map +1 -1
  27. package/lib/view/BorderButton.js +19 -38
  28. package/lib/view/BorderButton.js.map +1 -1
  29. package/lib/view/BorderTabSet.js +19 -8
  30. package/lib/view/BorderTabSet.js.map +1 -1
  31. package/lib/view/FloatingWindow.js +13 -5
  32. package/lib/view/FloatingWindow.js.map +1 -1
  33. package/lib/view/Icons.js +36 -0
  34. package/lib/view/Icons.js.map +1 -0
  35. package/lib/view/Layout.js +148 -71
  36. package/lib/view/Layout.js.map +1 -1
  37. package/lib/view/MenuTabButton.js +22 -0
  38. package/lib/view/MenuTabButton.js.map +1 -0
  39. package/lib/view/Splitter.js +3 -3
  40. package/lib/view/Splitter.js.map +1 -1
  41. package/lib/view/Tab.js +9 -6
  42. package/lib/view/Tab.js.map +1 -1
  43. package/lib/view/TabButton.js +20 -44
  44. package/lib/view/TabButton.js.map +1 -1
  45. package/lib/view/TabButtonStamp.js +22 -0
  46. package/lib/view/TabButtonStamp.js.map +1 -0
  47. package/lib/view/TabFloating.js +29 -15
  48. package/lib/view/TabFloating.js.map +1 -1
  49. package/lib/view/TabOverflowHook.js +1 -1
  50. package/lib/view/TabSet.js +40 -25
  51. package/lib/view/TabSet.js.map +1 -1
  52. package/lib/view/Utils.js +61 -0
  53. package/lib/view/Utils.js.map +1 -0
  54. package/package.json +11 -6
  55. package/src/I18nLabel.ts +1 -1
  56. package/src/PopupMenu.tsx +54 -15
  57. package/src/Types.ts +7 -0
  58. package/src/model/BorderNode.ts +8 -7
  59. package/src/model/IJsonModel.ts +3 -0
  60. package/src/model/Model.ts +19 -3
  61. package/src/model/RowNode.ts +8 -5
  62. package/src/model/TabNode.ts +6 -1
  63. package/src/model/TabSetNode.ts +8 -4
  64. package/src/view/BorderButton.tsx +38 -43
  65. package/src/view/BorderTabSet.tsx +34 -7
  66. package/src/view/FloatingWindow.tsx +14 -6
  67. package/src/view/Icons.tsx +36 -0
  68. package/src/view/Layout.tsx +179 -88
  69. package/src/view/Splitter.tsx +4 -1
  70. package/src/view/Tab.tsx +17 -6
  71. package/src/view/TabButton.tsx +42 -55
  72. package/src/view/TabButtonStamp.tsx +47 -0
  73. package/src/view/TabFloating.tsx +47 -23
  74. package/src/view/TabOverflowHook.tsx +1 -1
  75. package/src/view/TabSet.tsx +71 -22
  76. package/src/view/Utils.tsx +71 -0
  77. package/style/_base.scss +146 -92
  78. package/style/dark.css +157 -129
  79. package/style/dark.css.map +1 -1
  80. package/style/dark.scss +31 -21
  81. package/style/gray.css +157 -129
  82. package/style/gray.css.map +1 -1
  83. package/style/gray.scss +30 -23
  84. package/style/light.css +157 -129
  85. package/style/light.css.map +1 -1
  86. package/style/light.scss +30 -20
  87. package/images/close.png +0 -0
  88. package/images/maximize.png +0 -0
  89. package/images/more.png +0 -0
  90. package/images/more2.png +0 -0
  91. package/images/popout.png +0 -0
  92. package/images/restore.png +0 -0
@@ -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, ITitleObject } from "./Layout";
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, show, selected, iconFactory, titleFactory, icons } = props;
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
- if (!layout.getEditingTab()) {
32
- const message = layout.i18nName(I18nLabel.Move_Tab, node.getName());
33
- layout.dragStart(event, message, node, node.isEnableDrag(), onClick, onDoubleClick);
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 = contentRef.current!.getBoundingClientRect().width;
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
- let leadingContent = iconFactory ? iconFactory(node) : undefined;
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
- node._setRenderedName(renderState.name);
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 = <div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_LEADING)}>{renderState.leading}</div>;
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 key="close" title={closeTitle} className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TRAILING)} onMouseDown={onCloseMouseDown} onClick={onClose} onTouchStart={onCloseMouseDown}>
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
- style={{
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
+ };
@@ -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
- if (node.getWindow()) {
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
- layout.doAction(Actions.unFloatTab(node.getId()));
48
+ dockPopout();
39
49
  };
40
50
 
41
51
  const cm = layout.getClassName;
42
52
 
43
- const style: Record<string, any> = node._styleWithPosition({
44
- display: selected ? "flex" : "none",
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
- return (
52
- <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
53
- <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING_INNER)}>
54
- <div>{message}</div>
55
- <div>
56
- <a href="#" onClick={onClickFocus}>
57
- {showMessage}
58
- </a>
59
- </div>
60
- <div>
61
- <a href="#" onClick={onClickDock}>
62
- {dockMessage}
63
- </a>
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
- </div>
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 ? 10 : 0) : 45; // will need hidden tabs
95
+ endPos -= hiddenTabs.length > 0 ? (orientation === Orientation.HORZ ? 16 : 0) : 45; // will need hidden tabs
96
96
 
97
97
  let shiftPos = 0;
98
98
 
@@ -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(layout.getRootDiv(), element, hiddenTabs, onOverflowItemSelect, layout.getClassName);
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
- let name = node.getName();
46
- if (name === undefined) {
47
- name = "";
48
- } else {
49
- name = ": " + name;
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
- layout.doAction(Actions.setActiveTabset(node.getId()));
52
- if (!layout.getEditingTab()) {
53
- const message = layout.i18nName(I18nLabel.Move_Tabset, name);
54
- layout.dragStart(event, message, node, node.isEnableDrag(), (event2: Event) => undefined, onDoubleClick);
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.display = "none";
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" }} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
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} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
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} style={style} className={cm(CLASSES.FLEXLAYOUT__TABSET)} onWheel={onMouseWheel}>
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
+