flexlayout-react 0.5.16 → 0.5.20

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 (81) hide show
  1. package/ChangeLog.txt +24 -0
  2. package/README.md +128 -97
  3. package/declarations/DragDrop.d.ts +1 -0
  4. package/declarations/Rect.d.ts +4 -0
  5. package/declarations/Types.d.ts +8 -1
  6. package/declarations/model/BorderNode.d.ts +2 -1
  7. package/declarations/model/IJsonModel.d.ts +8 -0
  8. package/declarations/model/Model.d.ts +1 -0
  9. package/declarations/view/Layout.d.ts +19 -6
  10. package/dist/flexlayout.js +19 -19
  11. package/dist/flexlayout_min.js +1 -1
  12. package/lib/DockLocation.js +25 -11
  13. package/lib/DockLocation.js.map +1 -1
  14. package/lib/DragDrop.js +19 -3
  15. package/lib/DragDrop.js.map +1 -1
  16. package/lib/PopupMenu.js +14 -9
  17. package/lib/PopupMenu.js.map +1 -1
  18. package/lib/Rect.js +3 -0
  19. package/lib/Rect.js.map +1 -1
  20. package/lib/Types.js +7 -0
  21. package/lib/Types.js.map +1 -1
  22. package/lib/model/BorderNode.js +61 -14
  23. package/lib/model/BorderNode.js.map +1 -1
  24. package/lib/model/BorderSet.js +33 -19
  25. package/lib/model/BorderSet.js.map +1 -1
  26. package/lib/model/Model.js +23 -3
  27. package/lib/model/Model.js.map +1 -1
  28. package/lib/model/RowNode.js +19 -5
  29. package/lib/model/RowNode.js.map +1 -1
  30. package/lib/model/TabNode.js +10 -0
  31. package/lib/model/TabNode.js.map +1 -1
  32. package/lib/model/TabSetNode.js +34 -19
  33. package/lib/model/TabSetNode.js.map +1 -1
  34. package/lib/view/BorderButton.js +17 -6
  35. package/lib/view/BorderButton.js.map +1 -1
  36. package/lib/view/BorderTabSet.js +17 -6
  37. package/lib/view/BorderTabSet.js.map +1 -1
  38. package/lib/view/Layout.js +232 -57
  39. package/lib/view/Layout.js.map +1 -1
  40. package/lib/view/Splitter.js +35 -4
  41. package/lib/view/Splitter.js.map +1 -1
  42. package/lib/view/Tab.js +2 -2
  43. package/lib/view/Tab.js.map +1 -1
  44. package/lib/view/TabButton.js +16 -7
  45. package/lib/view/TabButton.js.map +1 -1
  46. package/lib/view/TabFloating.js +24 -12
  47. package/lib/view/TabFloating.js.map +1 -1
  48. package/lib/view/TabSet.js +49 -24
  49. package/lib/view/TabSet.js.map +1 -1
  50. package/package.json +11 -6
  51. package/src/DockLocation.ts +30 -9
  52. package/src/DragDrop.ts +26 -3
  53. package/src/PopupMenu.tsx +32 -11
  54. package/src/Rect.ts +6 -2
  55. package/src/Types.ts +7 -0
  56. package/src/model/BorderNode.ts +57 -15
  57. package/src/model/BorderSet.ts +32 -19
  58. package/src/model/IJsonModel.ts +8 -0
  59. package/src/model/Model.ts +30 -3
  60. package/src/model/RowNode.ts +8 -5
  61. package/src/model/TabNode.ts +11 -0
  62. package/src/model/TabSetNode.ts +33 -19
  63. package/src/view/BorderButton.tsx +34 -6
  64. package/src/view/BorderTabSet.tsx +25 -5
  65. package/src/view/Layout.tsx +299 -82
  66. package/src/view/Splitter.tsx +53 -4
  67. package/src/view/Tab.tsx +8 -2
  68. package/src/view/TabButton.tsx +31 -7
  69. package/src/view/TabFloating.tsx +42 -20
  70. package/src/view/TabSet.tsx +70 -18
  71. package/style/_base.scss +78 -51
  72. package/style/dark.css +94 -68
  73. package/style/dark.css.map +1 -1
  74. package/style/dark.scss +20 -20
  75. package/style/gray.css +94 -68
  76. package/style/gray.css.map +1 -1
  77. package/style/gray.scss +20 -20
  78. package/style/light.css +94 -68
  79. package/style/light.css.map +1 -1
  80. package/style/light.scss +18 -18
  81. package/yarn-error.log +0 -11828
@@ -13,17 +13,19 @@ import { ILayoutCallbacks } from "./Layout";
13
13
  export interface ISplitterProps {
14
14
  layout: ILayoutCallbacks;
15
15
  node: SplitterNode;
16
+ path: string;
16
17
  }
17
18
 
18
19
  /** @hidden @internal */
19
20
  export const Splitter = (props: ISplitterProps) => {
20
- const { layout, node } = props;
21
+ const { layout, node, path } = props;
21
22
 
22
23
  const pBounds = React.useRef<number[]>([]);
23
24
  const outlineDiv = React.useRef<HTMLDivElement | undefined>(undefined);
24
25
  const parentNode = node.getParent() as RowNode | BorderNode;
25
26
 
26
27
  const onMouseDown = (event: Event | React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
28
+ DragDrop.instance.setGlassCursorOverride(node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize");
27
29
  DragDrop.instance.startDrag(event, onDragStart, onDragMove, onDragEnd, onDragCancel, undefined, undefined, layout.getCurrentDocument(), layout.getRootDiv());
28
30
  pBounds.current = parentNode._getSplitterBounds(node, true);
29
31
  const rootdiv = layout.getRootDiv();
@@ -31,7 +33,14 @@ export const Splitter = (props: ISplitterProps) => {
31
33
  outlineDiv.current.style.position = "absolute";
32
34
  outlineDiv.current.className = layout.getClassName(CLASSES.FLEXLAYOUT__SPLITTER_DRAG);
33
35
  outlineDiv.current.style.cursor = node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize";
34
- node.getRect().positionElement(outlineDiv.current);
36
+ const r = node.getRect();
37
+ if (node.getOrientation() === Orientation.VERT && r.width < 2) {
38
+ r.width = 2;
39
+ } else if (node.getOrientation() === Orientation.HORZ && r.height < 2) {
40
+ r.height = 2;
41
+ }
42
+
43
+ r.positionElement(outlineDiv.current);
35
44
  rootdiv.appendChild(outlineDiv.current);
36
45
  };
37
46
 
@@ -106,7 +115,8 @@ export const Splitter = (props: ISplitterProps) => {
106
115
  };
107
116
 
108
117
  const cm = layout.getClassName;
109
- const style = node._styleWithPosition({
118
+ let r = node.getRect();
119
+ const style = r.styleWithPosition({
110
120
  cursor: node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize",
111
121
  });
112
122
  let className = cm(CLASSES.FLEXLAYOUT__SPLITTER) + " " + cm(CLASSES.FLEXLAYOUT__SPLITTER_ + node.getOrientation().getName());
@@ -119,5 +129,44 @@ export const Splitter = (props: ISplitterProps) => {
119
129
  }
120
130
  }
121
131
 
122
- return <div style={style} onTouchStart={onMouseDown} onMouseDown={onMouseDown} className={className} />;
132
+ const extra = node.getModel().getSplitterExtra();
133
+ if (extra === 0) {
134
+ return (<div
135
+ style={style}
136
+ data-layout-path={path}
137
+ className={className}
138
+ onTouchStart={onMouseDown}
139
+ onMouseDown={onMouseDown}>
140
+ </div>);
141
+ } else {
142
+ // add extended transparent div for hit testing
143
+ // extends forward only, so as not to interfere with scrollbars
144
+ let r2 = r.clone();
145
+ r2.x = 0;
146
+ r2.y = 0;
147
+ if (node.getOrientation() === Orientation.VERT) {
148
+ r2.width += extra;
149
+ } else {
150
+ r2.height += extra;
151
+ }
152
+ const style2 = r2.styleWithPosition({
153
+ cursor: node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize"
154
+ });
155
+
156
+ const className2 = cm(CLASSES.FLEXLAYOUT__SPLITTER_EXTRA);
157
+
158
+ return (
159
+ <div
160
+ style={style}
161
+ data-layout-path={path}
162
+ className={className}>
163
+ <div
164
+ style={style2}
165
+ className={className2}
166
+ onTouchStart={onMouseDown}
167
+ onMouseDown={onMouseDown}>
168
+ </div>
169
+ </div>);
170
+ }
171
+
123
172
  };
package/src/view/Tab.tsx CHANGED
@@ -15,11 +15,12 @@ export interface ITabProps {
15
15
  selected: boolean;
16
16
  node: TabNode;
17
17
  factory: (node: TabNode) => React.ReactNode;
18
+ path: string;
18
19
  }
19
20
 
20
21
  /** @hidden @internal */
21
22
  export const Tab = (props: ITabProps) => {
22
- const { layout, selected, node, factory } = props;
23
+ const { layout, selected, node, factory, path } = props;
23
24
  const [renderComponent, setRenderComponent] = React.useState<boolean>(!props.node.isEnableRenderOnDemand() || props.selected);
24
25
 
25
26
  React.useLayoutEffect(() => {
@@ -64,7 +65,12 @@ export const Tab = (props: ITabProps) => {
64
65
  }
65
66
 
66
67
  return (
67
- <div className={className} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
68
+ <div
69
+ className={className}
70
+ data-layout-path={path}
71
+ onMouseDown={onMouseDown}
72
+ onTouchStart={onMouseDown}
73
+ style={style}>
68
74
  <ErrorBoundary message={props.layout.i18nName(I18nLabel.Error_rendering_component)}>
69
75
  <Fragment>{child}</Fragment>
70
76
  </ErrorBoundary>
@@ -7,6 +7,7 @@ import Rect from "../Rect";
7
7
  import { IIcons, ILayoutCallbacks, ITitleObject } from "./Layout";
8
8
  import { ICloseType } from "../model/ICloseType";
9
9
  import { CLASSES } from "../Types";
10
+ import { isAuxMouseEvent } from "./TabSet";
10
11
 
11
12
  /** @hidden @internal */
12
13
  export interface ITabButtonProps {
@@ -18,22 +19,34 @@ export interface ITabButtonProps {
18
19
  iconFactory?: (node: TabNode) => React.ReactNode | undefined;
19
20
  titleFactory?: (node: TabNode) => React.ReactNode | undefined;
20
21
  icons?: IIcons;
22
+ path: string;
21
23
  }
22
24
 
23
25
  /** @hidden @internal */
24
26
  export const TabButton = (props: ITabButtonProps) => {
25
- const { layout, node, show, selected, iconFactory, titleFactory, icons } = props;
27
+ const { layout, node, show, selected, iconFactory, titleFactory, icons, path } = props;
26
28
  const selfRef = React.useRef<HTMLDivElement | null>(null);
27
29
  const contentRef = React.useRef<HTMLInputElement | null>(null);
28
30
  const contentWidth = React.useRef<number>(0);
29
31
 
30
32
  const onMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
31
- if (!layout.getEditingTab()) {
33
+
34
+ if (!isAuxMouseEvent(event) && !layout.getEditingTab()) {
32
35
  const message = layout.i18nName(I18nLabel.Move_Tab, node.getName());
33
36
  layout.dragStart(event, message, node, node.isEnableDrag(), onClick, onDoubleClick);
34
37
  }
35
38
  };
36
39
 
40
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
41
+ if (isAuxMouseEvent(event)) {
42
+ layout.auxMouseClick(node, event);
43
+ }
44
+ };
45
+
46
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
47
+ layout.showContextMenu(node, event);
48
+ };
49
+
37
50
  const onClick = () => {
38
51
  layout.doAction(Actions.selectTab(node.getId()));
39
52
  };
@@ -43,7 +56,7 @@ export const TabButton = (props: ITabButtonProps) => {
43
56
  layout.setEditingTab(node);
44
57
  layout.getCurrentDocument()!.body.addEventListener("mousedown", onEndEdit);
45
58
  layout.getCurrentDocument()!.body.addEventListener("touchstart", onEndEdit);
46
- }
59
+ }
47
60
  // else {
48
61
  // const parentNode = node.getParent() as TabSetNode;
49
62
  // if (parentNode.canMaximize()) {
@@ -140,8 +153,8 @@ export const TabButton = (props: ITabButtonProps) => {
140
153
  let name = node.getName();
141
154
 
142
155
  function isTitleObject(obj: any): obj is ITitleObject {
143
- return obj.titleContent !== undefined
144
- }
156
+ return obj.titleContent !== undefined
157
+ }
145
158
 
146
159
  if (titleFactory !== undefined) {
147
160
  const titleObj = titleFactory(node);
@@ -158,7 +171,7 @@ export const TabButton = (props: ITabButtonProps) => {
158
171
  }
159
172
  }
160
173
 
161
- if (typeof leadingContent === undefined && typeof node.getIcon() !== undefined) {
174
+ if (leadingContent === undefined && node.getIcon() !== undefined) {
162
175
  leadingContent = <img src={node.getIcon()} alt="leadingContent" />;
163
176
  }
164
177
 
@@ -184,6 +197,7 @@ export const TabButton = (props: ITabButtonProps) => {
184
197
  style={contentStyle}
185
198
  ref={contentRef}
186
199
  className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TEXTBOX)}
200
+ data-layout-path={path + "/textbox"}
187
201
  type="text"
188
202
  autoFocus={true}
189
203
  defaultValue={node.getName()}
@@ -197,7 +211,13 @@ export const TabButton = (props: ITabButtonProps) => {
197
211
  if (node.isEnableClose()) {
198
212
  const closeTitle = layout.i18nName(I18nLabel.Close_Tab);
199
213
  buttons.push(
200
- <div key="close" title={closeTitle} className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TRAILING)} onMouseDown={onCloseMouseDown} onClick={onClose} onTouchStart={onCloseMouseDown}>
214
+ <div
215
+ key="close"
216
+ data-layout-path={path + "/button/close"}
217
+ title={closeTitle}
218
+ className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_TRAILING)}
219
+ onMouseDown={onCloseMouseDown} onClick={onClose}
220
+ onTouchStart={onCloseMouseDown}>
201
221
  {icons?.close}
202
222
  </div>
203
223
  );
@@ -206,11 +226,15 @@ export const TabButton = (props: ITabButtonProps) => {
206
226
  return (
207
227
  <div
208
228
  ref={selfRef}
229
+ data-layout-path={path}
209
230
  style={{
210
231
  visibility: show ? "visible" : "hidden",
211
232
  }}
212
233
  className={classNames}
213
234
  onMouseDown={onMouseDown}
235
+ onClick={onAuxMouseClick}
236
+ onAuxClick={onAuxMouseClick}
237
+ onContextMenu={onContextMenu}
214
238
  onTouchStart={onMouseDown}
215
239
  title={node.getHelpText()}
216
240
  >
@@ -11,11 +11,22 @@ export interface ITabFloatingProps {
11
11
  layout: ILayoutCallbacks;
12
12
  selected: boolean;
13
13
  node: TabNode;
14
+ path: string;
14
15
  }
15
16
 
16
17
  /** @hidden @internal */
17
18
  export const TabFloating = (props: ITabFloatingProps) => {
18
- const { layout, selected, node } = props;
19
+ const { layout, selected, node, path } = props;
20
+
21
+ const showPopout = () => {
22
+ if (node.getWindow()) {
23
+ node.getWindow()!.focus();
24
+ }
25
+ }
26
+
27
+ const dockPopout = () => {
28
+ layout.doAction(Actions.unFloatTab(node.getId()));
29
+ }
19
30
 
20
31
  const onMouseDown = () => {
21
32
  const parent = node.getParent() as TabSetNode;
@@ -28,14 +39,12 @@ export const TabFloating = (props: ITabFloatingProps) => {
28
39
 
29
40
  const onClickFocus = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
30
41
  event.preventDefault();
31
- if (node.getWindow()) {
32
- node.getWindow()!.focus();
33
- }
42
+ showPopout();
34
43
  };
35
44
 
36
45
  const onClickDock = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
37
46
  event.preventDefault();
38
- layout.doAction(Actions.unFloatTab(node.getId()));
47
+ dockPopout();
39
48
  };
40
49
 
41
50
  const cm = layout.getClassName;
@@ -48,21 +57,34 @@ export const TabFloating = (props: ITabFloatingProps) => {
48
57
  const showMessage = layout.i18nName(I18nLabel.Floating_Window_Show_Window);
49
58
  const dockMessage = layout.i18nName(I18nLabel.Floating_Window_Dock_Window);
50
59
 
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>
60
+ const customRenderCallback = layout.getOnRenderFloatingTabPlaceholder();
61
+ if (customRenderCallback) {
62
+ return (
63
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
64
+ {customRenderCallback(dockPopout, showPopout)}
65
+ </div>
66
+ );
67
+ } else {
68
+ return (
69
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)}
70
+ data-layout-path={path}
71
+ onMouseDown={onMouseDown}
72
+ onTouchStart={onMouseDown}
73
+ style={style}>
74
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING_INNER)}>
75
+ <div>{message}</div>
76
+ <div>
77
+ <a href="#" onClick={onClickFocus}>
78
+ {showMessage}
79
+ </a>
80
+ </div>
81
+ <div>
82
+ <a href="#" onClick={onClickDock}>
83
+ {dockMessage}
84
+ </a>
85
+ </div>
64
86
  </div>
65
87
  </div>
66
- </div>
67
- );
88
+ );
89
+ }
68
90
  };
@@ -17,12 +17,13 @@ export interface ITabSetProps {
17
17
  iconFactory?: (node: TabNode) => React.ReactNode | undefined;
18
18
  titleFactory?: (node: TabNode) => React.ReactNode | undefined;
19
19
  icons?: IIcons;
20
- editingTab?: TabNode;
20
+ editingTab?: TabNode;
21
+ path?: string;
21
22
  }
22
23
 
23
24
  /** @hidden @internal */
24
25
  export const TabSet = (props: ITabSetProps) => {
25
- const { node, layout, iconFactory, titleFactory, icons } = props;
26
+ const { node, layout, iconFactory, titleFactory, icons, path } = props;
26
27
 
27
28
  const toolbarRef = React.useRef<HTMLDivElement | null>(null);
28
29
  const overflowbuttonRef = React.useRef<HTMLButtonElement | null>(null);
@@ -31,9 +32,10 @@ export const TabSet = (props: ITabSetProps) => {
31
32
 
32
33
  const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel, tabsTruncated } = useTabOverflow(node, Orientation.HORZ, toolbarRef, stickyButtonsRef);
33
34
 
34
- const onOverflowClick = () => {
35
+ const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
35
36
  const element = overflowbuttonRef.current!;
36
37
  showPopup(layout.getRootDiv(), element, hiddenTabs, onOverflowItemSelect, layout.getClassName);
38
+ event.stopPropagation();
37
39
  };
38
40
 
39
41
  const onOverflowItemSelect = (item: { node: TabNode; index: number }) => {
@@ -42,37 +44,52 @@ export const TabSet = (props: ITabSetProps) => {
42
44
  };
43
45
 
44
46
  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;
47
+ if (!isAuxMouseEvent(event)) {
48
+ let name = node.getName();
49
+ if (name === undefined) {
50
+ name = "";
51
+ } else {
52
+ name = ": " + name;
53
+ }
54
+ layout.doAction(Actions.setActiveTabset(node.getId()));
55
+ if (!layout.getEditingTab()) {
56
+ const message = layout.i18nName(I18nLabel.Move_Tabset, name);
57
+ layout.dragStart(event, message, node, node.isEnableDrag(), (event2: Event) => undefined, onDoubleClick);
58
+ }
50
59
  }
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);
60
+ };
61
+
62
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
63
+ if (isAuxMouseEvent(event)) {
64
+ layout.auxMouseClick(node, event);
55
65
  }
56
66
  };
57
67
 
68
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
69
+ layout.showContextMenu(node, event);
70
+ };
71
+
58
72
  const onInterceptMouseDown = (event: React.MouseEvent | React.TouchEvent) => {
59
73
  event.stopPropagation();
60
74
  };
61
75
 
62
- const onMaximizeToggle = () => {
76
+ const onMaximizeToggle = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
63
77
  if (node.canMaximize()) {
64
78
  layout.maximize(node);
65
79
  }
80
+ event.stopPropagation();
66
81
  };
67
82
 
68
- const onClose = () => {
83
+ const onClose = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
69
84
  layout.doAction(Actions.deleteTabset(node.getId()));
85
+ event.stopPropagation();
70
86
  };
71
87
 
72
- const onFloatTab = () => {
88
+ const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
73
89
  if (selectedTabNode !== undefined) {
74
90
  layout.doAction(Actions.floatTab(selectedTabNode.getId()));
75
91
  }
92
+ event.stopPropagation();
76
93
  };
77
94
 
78
95
  const onDoubleClick = (event: Event) => {
@@ -105,6 +122,7 @@ export const TabSet = (props: ITabSetProps) => {
105
122
  <TabButton
106
123
  layout={layout}
107
124
  node={child}
125
+ path={path + "/tb" + i}
108
126
  key={child.getId()}
109
127
  selected={isSelected}
110
128
  show={true}
@@ -153,6 +171,8 @@ export const TabSet = (props: ITabSetProps) => {
153
171
  buttons.push(
154
172
  <button
155
173
  key="overflowbutton"
174
+ data-layout-path={path + "/button/overflow"}
175
+
156
176
  ref={overflowbuttonRef}
157
177
  className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
158
178
  title={overflowTitle}
@@ -171,6 +191,7 @@ export const TabSet = (props: ITabSetProps) => {
171
191
  buttons.push(
172
192
  <button
173
193
  key="float"
194
+ data-layout-path={path + "/button/float"}
174
195
  title={floatTitle}
175
196
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_FLOAT)}
176
197
  onClick={onFloatTab}
@@ -188,6 +209,7 @@ export const TabSet = (props: ITabSetProps) => {
188
209
  btns.push(
189
210
  <button
190
211
  key="max"
212
+ data-layout-path={path + "/button/max"}
191
213
  title={node.isMaximized() ? minTitle : maxTitle}
192
214
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_ + (node.isMaximized() ? "max" : "min"))}
193
215
  onClick={onMaximizeToggle}
@@ -205,6 +227,7 @@ export const TabSet = (props: ITabSetProps) => {
205
227
  btns.push(
206
228
  <button
207
229
  key="close"
230
+ data-layout-path={path + "/button/close"}
208
231
  title={title}
209
232
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE)}
210
233
  onClick={onClose}
@@ -269,7 +292,13 @@ export const TabSet = (props: ITabSetProps) => {
269
292
  }
270
293
 
271
294
  header = (
272
- <div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
295
+ <div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }}
296
+ data-layout-path={path + "/header"}
297
+ onMouseDown={onMouseDown}
298
+ onContextMenu={onContextMenu}
299
+ onClick={onAuxMouseClick}
300
+ onAuxClick={onAuxMouseClick}
301
+ onTouchStart={onMouseDown}>
273
302
  <div className={cm(CLASSES.FLEXLAYOUT__TABSET_HEADER_CONTENT)}>{headerContent}</div>
274
303
  {headerToolbar}
275
304
  </div>
@@ -284,7 +313,13 @@ export const TabSet = (props: ITabSetProps) => {
284
313
  tabStripStyle["bottom"] = "0px";
285
314
  }
286
315
  tabStrip = (
287
- <div className={tabStripClasses} style={tabStripStyle} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
316
+ <div className={tabStripClasses} style={tabStripStyle}
317
+ data-layout-path={path + "/tabstrip"}
318
+ onMouseDown={onMouseDown}
319
+ onContextMenu={onContextMenu}
320
+ onClick={onAuxMouseClick}
321
+ onAuxClick={onAuxMouseClick}
322
+ onTouchStart={onMouseDown}>
288
323
  <div ref={tabbarInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
289
324
  <div
290
325
  style={{ left: position }}
@@ -300,9 +335,26 @@ export const TabSet = (props: ITabSetProps) => {
300
335
  style = layout.styleFont(style);
301
336
 
302
337
  return (
303
- <div ref={selfRef} style={style} className={cm(CLASSES.FLEXLAYOUT__TABSET)} onWheel={onMouseWheel}>
338
+ <div ref={selfRef}
339
+ dir="ltr"
340
+ data-layout-path={path}
341
+ style={style}
342
+ className={cm(CLASSES.FLEXLAYOUT__TABSET)}
343
+ onWheel={onMouseWheel}>
304
344
  {header}
305
345
  {tabStrip}
306
346
  </div>
307
347
  );
308
348
  };
349
+
350
+ /** @hidden @internal */
351
+ export function isAuxMouseEvent(event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) {
352
+ let auxEvent = false;
353
+ if (event.nativeEvent instanceof MouseEvent) {
354
+ if (event.nativeEvent.button !== 0 || event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) {
355
+ auxEvent = true;
356
+ }
357
+ }
358
+ return auxEvent;
359
+ }
360
+