flexlayout-react 0.5.18 → 0.5.19

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 (53) hide show
  1. package/ChangeLog.txt +8 -0
  2. package/README.md +109 -96
  3. package/declarations/Types.d.ts +7 -1
  4. package/declarations/view/Layout.d.ts +5 -0
  5. package/dist/flexlayout.js +12 -12
  6. package/dist/flexlayout_min.js +1 -1
  7. package/lib/PopupMenu.js +14 -9
  8. package/lib/PopupMenu.js.map +1 -1
  9. package/lib/Types.js +6 -0
  10. package/lib/Types.js.map +1 -1
  11. package/lib/model/BorderNode.js +8 -7
  12. package/lib/model/BorderNode.js.map +1 -1
  13. package/lib/model/Model.js +7 -3
  14. package/lib/model/Model.js.map +1 -1
  15. package/lib/model/RowNode.js +19 -5
  16. package/lib/model/RowNode.js.map +1 -1
  17. package/lib/model/TabSetNode.js +8 -4
  18. package/lib/model/TabSetNode.js.map +1 -1
  19. package/lib/view/BorderButton.js +14 -3
  20. package/lib/view/BorderButton.js.map +1 -1
  21. package/lib/view/BorderTabSet.js +15 -4
  22. package/lib/view/BorderTabSet.js.map +1 -1
  23. package/lib/view/Layout.js +81 -48
  24. package/lib/view/Layout.js.map +1 -1
  25. package/lib/view/TabButton.js +11 -2
  26. package/lib/view/TabButton.js.map +1 -1
  27. package/lib/view/TabFloating.js +23 -11
  28. package/lib/view/TabFloating.js.map +1 -1
  29. package/lib/view/TabSet.js +43 -18
  30. package/lib/view/TabSet.js.map +1 -1
  31. package/package.json +1 -1
  32. package/src/PopupMenu.tsx +28 -10
  33. package/src/Types.ts +6 -0
  34. package/src/model/BorderNode.ts +8 -7
  35. package/src/model/Model.ts +7 -3
  36. package/src/model/RowNode.ts +8 -5
  37. package/src/model/TabSetNode.ts +8 -4
  38. package/src/view/BorderButton.tsx +22 -3
  39. package/src/view/BorderTabSet.tsx +21 -4
  40. package/src/view/Layout.tsx +100 -58
  41. package/src/view/TabButton.tsx +16 -1
  42. package/src/view/TabFloating.tsx +36 -19
  43. package/src/view/TabSet.tsx +56 -17
  44. package/style/_base.scss +65 -41
  45. package/style/dark.css +81 -59
  46. package/style/dark.css.map +1 -1
  47. package/style/dark.scss +20 -20
  48. package/style/gray.css +81 -59
  49. package/style/gray.css.map +1 -1
  50. package/style/gray.scss +20 -20
  51. package/style/light.css +81 -59
  52. package/style/light.css.map +1 -1
  53. package/style/light.scss +18 -18
@@ -10,6 +10,7 @@ import { I18nLabel } from "../I18nLabel";
10
10
  import { useTabOverflow } from "./TabOverflowHook";
11
11
  import Orientation from "../Orientation";
12
12
  import { CLASSES } from "../Types";
13
+ import { isAuxMouseEvent } from "./TabSet";
13
14
 
14
15
  /** @hidden @internal */
15
16
  export interface IBorderTabSetProps {
@@ -30,13 +31,24 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
30
31
 
31
32
  const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel } = useTabOverflow(border, Orientation.flip(border.getOrientation()), toolbarRef, stickyButtonsRef);
32
33
 
34
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
35
+ if (isAuxMouseEvent(event)) {
36
+ layout.auxMouseClick(border, event);
37
+ }
38
+ };
39
+
40
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
41
+ layout.showContextMenu(border, event);
42
+ };
43
+
33
44
  const onInterceptMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.MouseEvent<HTMLButtonElement, MouseEvent> | React.TouchEvent<HTMLButtonElement>) => {
34
45
  event.stopPropagation();
35
46
  };
36
47
 
37
- const onOverflowClick = () => {
48
+ const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
38
49
  const element = overflowbuttonRef.current!;
39
50
  showPopup(layout.getRootDiv(), element, hiddenTabs, onOverflowItemSelect, layout.getClassName);
51
+ event.stopPropagation();
40
52
  };
41
53
 
42
54
  const onOverflowItemSelect = (item: { node: TabNode; index: number }) => {
@@ -44,11 +56,12 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
44
56
  userControlledLeft.current = false;
45
57
  };
46
58
 
47
- const onFloatTab = () => {
59
+ const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
48
60
  const selectedTabNode = border.getChildren()[border.getSelected()] as TabNode;
49
61
  if (selectedTabNode !== undefined) {
50
62
  layout.doAction(Actions.floatTab(selectedTabNode.getId()));
51
63
  }
64
+ event.stopPropagation();
52
65
  };
53
66
 
54
67
  const cm = layout.getClassName;
@@ -97,7 +110,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
97
110
  <button
98
111
  key="overflowbutton"
99
112
  ref={overflowbuttonRef}
100
- className={cm("flexlayout__border_toolbar_button_overflow") + " " + cm("flexlayout__border_toolbar_button_overflow_" + border.getLocation().getName())}
113
+ className={cm(CLASSES.FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW_ + border.getLocation().getName())}
101
114
  title={overflowTitle}
102
115
  onClick={onOverflowClick}
103
116
  onMouseDown={onInterceptMouseDown}
@@ -145,7 +158,11 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
145
158
  }
146
159
 
147
160
  return (
148
- <div ref={selfRef} style={style} className={borderClasses} onWheel={onMouseWheel}>
161
+ <div ref={selfRef} dir="ltr" style={style} className={borderClasses}
162
+ onClick={onAuxMouseClick}
163
+ onAuxClick={onAuxMouseClick}
164
+ onContextMenu={onContextMenu}
165
+ onWheel={onMouseWheel}>
149
166
  <div style={{ height: borderHeight }} className={cm(CLASSES.FLEXLAYOUT__BORDER_INNER) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_INNER_ + border.getLocation().getName())}>
150
167
  <div style={innerStyle} className={cm(CLASSES.FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER_ + border.getLocation().getName())}>
151
168
  {tabs}
@@ -28,6 +28,8 @@ import { IJsonTabNode } from "../model/IJsonModel";
28
28
 
29
29
  export type CustomDragCallback = (dragging: TabNode | IJsonTabNode, over: TabNode, x: number, y: number, location: DockLocation) => void;
30
30
  export type DragRectRenderCallback = (text: String, node?: Node, json?: IJsonTabNode) => React.ReactElement | undefined;
31
+ export type FloatingTabPlaceholderRenderCallback = (dockPopout: () => void, showPopout: () => void) => React.ReactElement | undefined;
32
+ export type NodeMouseEvent = (node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
31
33
 
32
34
  export interface ILayoutProps {
33
35
  model: Model;
@@ -41,11 +43,11 @@ export interface ILayoutProps {
41
43
  onAction?: (action: Action) => Action | undefined;
42
44
  onRenderTab?: (
43
45
  node: TabNode,
44
- renderValues: ITabRenderValues,
46
+ renderValues: ITabRenderValues, // change the values in this object as required
45
47
  ) => void;
46
48
  onRenderTabSet?: (
47
49
  tabSetNode: TabSetNode | BorderNode,
48
- renderValues: ITabSetRenderValues,
50
+ renderValues: ITabSetRenderValues, // change the values in this object as required
49
51
  ) => void;
50
52
  onModelChange?: (model: Model) => void;
51
53
  onExternalDrag?: (event: React.DragEvent<HTMLDivElement>) => undefined | {
@@ -69,6 +71,9 @@ export interface ILayoutProps {
69
71
  cursor?: string | undefined
70
72
  };
71
73
  onRenderDragRect?: DragRectRenderCallback;
74
+ onRenderFloatingTabPlaceholder?: FloatingTabPlaceholderRenderCallback;
75
+ onContextMenu?: NodeMouseEvent;
76
+ onAuxMouseClick?: NodeMouseEvent;
72
77
  }
73
78
  export interface IFontValues {
74
79
  size?: string;
@@ -157,7 +162,9 @@ export interface ILayoutCallbacks {
157
162
  styleFont: (style: Record<string, string>) => Record<string, string>;
158
163
  setEditingTab(tabNode?: TabNode): void;
159
164
  getEditingTab(): TabNode | undefined;
160
-
165
+ getOnRenderFloatingTabPlaceholder(): FloatingTabPlaceholderRenderCallback | undefined;
166
+ showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) : void;
167
+ auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) : void;
161
168
  }
162
169
 
163
170
  // Popout windows work in latest browsers based on webkit (Chrome, Opera, Safari, latest Edge) and Firefox. They do
@@ -683,7 +690,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
683
690
 
684
691
  this.dragDivText = dragText;
685
692
  this.dragDiv = this.currentDocument!.createElement("div");
686
- this.dragDiv.className = this.getClassName("flexlayout__drag_rect");
693
+ this.dragDiv.className = this.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT);
687
694
  this.dragDiv.addEventListener("mousedown", this.onDragDivMouseDown);
688
695
  this.dragDiv.addEventListener("touchstart", this.onDragDivMouseDown);
689
696
 
@@ -867,62 +874,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
867
874
 
868
875
  let dropInfo = this.props.model._findDropTargetNode(this.dragNode!, pos.x, pos.y);
869
876
  if (dropInfo) {
870
- let invalidated = this.customDrop?.invalidated;
871
- const currentCallback = this.customDrop?.callback;
872
- this.customDrop = undefined;
873
-
874
- const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
875
- if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
876
- const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
877
- const tabRect = selected?.getRect()
878
-
879
- if (selected && tabRect?.contains(pos.x, pos.y)) {
880
- let customDrop: ICustomDropDestination | undefined = undefined;
881
-
882
- try {
883
- const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location, () => this.onDragMove(event));
884
-
885
- if (dest) {
886
- customDrop = {
887
- rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
888
- callback: dest.callback,
889
- invalidated: dest.invalidated,
890
- dragging: dragging,
891
- over: selected,
892
- x: pos.x - tabRect.x,
893
- y: pos.y - tabRect.y,
894
- location: dropInfo.location,
895
- cursor: dest.cursor
896
- };
897
- }
898
- } catch (e) {
899
- console.error(e)
900
- }
901
-
902
- if (customDrop?.callback === currentCallback) {
903
- invalidated = undefined;
904
- }
905
-
906
- this.customDrop = customDrop;
907
- }
908
- }
909
-
910
- this.dropInfo = dropInfo;
911
- this.outlineDiv!.className = this.getClassName(this.customDrop ? "flexlayout__outline_rect" : dropInfo.className);
912
-
913
- if (this.customDrop) {
914
- this.customDrop.rect.positionElement(this.outlineDiv!);
877
+ if (this.props.onTabDrag) {
878
+ this.handleCustomTabDrag(dropInfo, pos, event);
915
879
  } else {
880
+ this.dropInfo = dropInfo;
881
+ this.outlineDiv!.className = this.getClassName(dropInfo.className);
916
882
  dropInfo.rect.positionElement(this.outlineDiv!);
917
- }
918
-
919
- DragDrop.instance.setGlassCursorOverride(this.customDrop?.cursor);
920
- this.outlineDiv!.style.visibility = "visible";
921
-
922
- try {
923
- invalidated?.();
924
- } catch (e) {
925
- console.error(e);
883
+ this.outlineDiv!.style.visibility = "visible";
926
884
  }
927
885
  }
928
886
  };
@@ -943,6 +901,10 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
943
901
  try {
944
902
  const { callback, dragging, over, x, y, location } = this.customDrop;
945
903
  callback(dragging, over, x, y, location);
904
+ if (this.fnNewNodeDropped != null) {
905
+ this.fnNewNodeDropped();
906
+ this.fnNewNodeDropped = undefined;
907
+ }
946
908
  } catch (e) {
947
909
  console.error(e)
948
910
  }
@@ -961,6 +923,67 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
961
923
  this.setState({ showHiddenBorder: DockLocation.CENTER });
962
924
  };
963
925
 
926
+ /** @hidden @internal */
927
+ private handleCustomTabDrag(dropInfo: DropInfo, pos: { x: number; y: number; }, event: React.MouseEvent<Element, MouseEvent>) {
928
+ let invalidated = this.customDrop?.invalidated;
929
+ const currentCallback = this.customDrop?.callback;
930
+ this.customDrop = undefined;
931
+
932
+ const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
933
+ if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
934
+ const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
935
+ const tabRect = selected?.getRect();
936
+
937
+ if (selected && tabRect?.contains(pos.x, pos.y)) {
938
+ let customDrop: ICustomDropDestination | undefined = undefined;
939
+
940
+ try {
941
+ const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location, () => this.onDragMove(event));
942
+
943
+ if (dest) {
944
+ customDrop = {
945
+ rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
946
+ callback: dest.callback,
947
+ invalidated: dest.invalidated,
948
+ dragging: dragging,
949
+ over: selected,
950
+ x: pos.x - tabRect.x,
951
+ y: pos.y - tabRect.y,
952
+ location: dropInfo.location,
953
+ cursor: dest.cursor
954
+ };
955
+ }
956
+ } catch (e) {
957
+ console.error(e);
958
+ }
959
+
960
+ if (customDrop?.callback === currentCallback) {
961
+ invalidated = undefined;
962
+ }
963
+
964
+ this.customDrop = customDrop;
965
+ }
966
+ }
967
+
968
+ this.dropInfo = dropInfo;
969
+ this.outlineDiv!.className = this.getClassName(this.customDrop ? CLASSES.FLEXLAYOUT__OUTLINE_RECT : dropInfo.className);
970
+
971
+ if (this.customDrop) {
972
+ this.customDrop.rect.positionElement(this.outlineDiv!);
973
+ } else {
974
+ dropInfo.rect.positionElement(this.outlineDiv!);
975
+ }
976
+
977
+ DragDrop.instance.setGlassCursorOverride(this.customDrop?.cursor);
978
+ this.outlineDiv!.style.visibility = "visible";
979
+
980
+ try {
981
+ invalidated?.();
982
+ } catch (e) {
983
+ console.error(e);
984
+ }
985
+ }
986
+
964
987
  /** @hidden @internal */
965
988
  onDragEnter(event: React.DragEvent<HTMLDivElement>) {
966
989
  // DragDrop keeps track of number of dragenters minus the number of
@@ -1125,6 +1148,25 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
1125
1148
  }
1126
1149
  return message;
1127
1150
  }
1151
+
1152
+ /** @hidden @internal */
1153
+ getOnRenderFloatingTabPlaceholder() {
1154
+ return this.props.onRenderFloatingTabPlaceholder;
1155
+ }
1156
+
1157
+ /** @hidden @internal */
1158
+ showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
1159
+ if (this.props.onContextMenu) {
1160
+ this.props.onContextMenu(node, event);
1161
+ }
1162
+ }
1163
+
1164
+ /** @hidden @internal */
1165
+ auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
1166
+ if (this.props.onAuxMouseClick) {
1167
+ this.props.onAuxMouseClick(node, event);
1168
+ }
1169
+ }
1128
1170
  }
1129
1171
 
1130
1172
  // wrapper round the drag rect renderer that can call
@@ -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 {
@@ -28,12 +29,23 @@ export const TabButton = (props: ITabButtonProps) => {
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
+
33
+ if (!isAuxMouseEvent(event) && !layout.getEditingTab()) {
32
34
  const message = layout.i18nName(I18nLabel.Move_Tab, node.getName());
33
35
  layout.dragStart(event, message, node, node.isEnableDrag(), onClick, onDoubleClick);
34
36
  }
35
37
  };
36
38
 
39
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
40
+ if (isAuxMouseEvent(event)) {
41
+ layout.auxMouseClick(node, event);
42
+ }
43
+ };
44
+
45
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
46
+ layout.showContextMenu(node, event);
47
+ };
48
+
37
49
  const onClick = () => {
38
50
  layout.doAction(Actions.selectTab(node.getId()));
39
51
  };
@@ -211,6 +223,9 @@ export const TabButton = (props: ITabButtonProps) => {
211
223
  }}
212
224
  className={classNames}
213
225
  onMouseDown={onMouseDown}
226
+ onClick={onAuxMouseClick}
227
+ onAuxClick={onAuxMouseClick}
228
+ onContextMenu={onContextMenu}
214
229
  onTouchStart={onMouseDown}
215
230
  title={node.getHelpText()}
216
231
  >
@@ -17,6 +17,16 @@ export interface ITabFloatingProps {
17
17
  export const TabFloating = (props: ITabFloatingProps) => {
18
18
  const { layout, selected, node } = props;
19
19
 
20
+ const showPopout = () => {
21
+ if (node.getWindow()) {
22
+ node.getWindow()!.focus();
23
+ }
24
+ }
25
+
26
+ const dockPopout = () => {
27
+ layout.doAction(Actions.unFloatTab(node.getId()));
28
+ }
29
+
20
30
  const onMouseDown = () => {
21
31
  const parent = node.getParent() as TabSetNode;
22
32
  if (parent.getType() === TabSetNode.TYPE) {
@@ -28,14 +38,12 @@ export const TabFloating = (props: ITabFloatingProps) => {
28
38
 
29
39
  const onClickFocus = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
30
40
  event.preventDefault();
31
- if (node.getWindow()) {
32
- node.getWindow()!.focus();
33
- }
41
+ showPopout();
34
42
  };
35
43
 
36
44
  const onClickDock = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
37
45
  event.preventDefault();
38
- layout.doAction(Actions.unFloatTab(node.getId()));
46
+ dockPopout();
39
47
  };
40
48
 
41
49
  const cm = layout.getClassName;
@@ -48,21 +56,30 @@ export const TabFloating = (props: ITabFloatingProps) => {
48
56
  const showMessage = layout.i18nName(I18nLabel.Floating_Window_Show_Window);
49
57
  const dockMessage = layout.i18nName(I18nLabel.Floating_Window_Dock_Window);
50
58
 
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>
59
+ const customRenderCallback = layout.getOnRenderFloatingTabPlaceholder();
60
+ if (customRenderCallback) {
61
+ return (
62
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
63
+ {customRenderCallback(dockPopout, showPopout)}
64
+ </div>
65
+ );
66
+ } else {
67
+ return (
68
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING)} onMouseDown={onMouseDown} onTouchStart={onMouseDown} style={style}>
69
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_FLOATING_INNER)}>
70
+ <div>{message}</div>
71
+ <div>
72
+ <a href="#" onClick={onClickFocus}>
73
+ {showMessage}
74
+ </a>
75
+ </div>
76
+ <div>
77
+ <a href="#" onClick={onClickDock}>
78
+ {dockMessage}
79
+ </a>
80
+ </div>
64
81
  </div>
65
82
  </div>
66
- </div>
67
- );
83
+ );
84
+ }
68
85
  };
@@ -17,7 +17,7 @@ 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
21
  }
22
22
 
23
23
  /** @hidden @internal */
@@ -31,9 +31,10 @@ export const TabSet = (props: ITabSetProps) => {
31
31
 
32
32
  const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel, tabsTruncated } = useTabOverflow(node, Orientation.HORZ, toolbarRef, stickyButtonsRef);
33
33
 
34
- const onOverflowClick = () => {
34
+ const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
35
35
  const element = overflowbuttonRef.current!;
36
36
  showPopup(layout.getRootDiv(), element, hiddenTabs, onOverflowItemSelect, layout.getClassName);
37
+ event.stopPropagation();
37
38
  };
38
39
 
39
40
  const onOverflowItemSelect = (item: { node: TabNode; index: number }) => {
@@ -42,37 +43,53 @@ export const TabSet = (props: ITabSetProps) => {
42
43
  };
43
44
 
44
45
  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;
46
+
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) => {
@@ -269,7 +286,12 @@ export const TabSet = (props: ITabSetProps) => {
269
286
  }
270
287
 
271
288
  header = (
272
- <div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
289
+ <div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }}
290
+ onMouseDown={onMouseDown}
291
+ onContextMenu={onContextMenu}
292
+ onClick={onAuxMouseClick}
293
+ onAuxClick={onAuxMouseClick}
294
+ onTouchStart={onMouseDown}>
273
295
  <div className={cm(CLASSES.FLEXLAYOUT__TABSET_HEADER_CONTENT)}>{headerContent}</div>
274
296
  {headerToolbar}
275
297
  </div>
@@ -284,7 +306,12 @@ export const TabSet = (props: ITabSetProps) => {
284
306
  tabStripStyle["bottom"] = "0px";
285
307
  }
286
308
  tabStrip = (
287
- <div className={tabStripClasses} style={tabStripStyle} onMouseDown={onMouseDown} onTouchStart={onMouseDown}>
309
+ <div className={tabStripClasses} style={tabStripStyle}
310
+ onMouseDown={onMouseDown}
311
+ onContextMenu={onContextMenu}
312
+ onClick={onAuxMouseClick}
313
+ onAuxClick={onAuxMouseClick}
314
+ onTouchStart={onMouseDown}>
288
315
  <div ref={tabbarInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
289
316
  <div
290
317
  style={{ left: position }}
@@ -300,9 +327,21 @@ export const TabSet = (props: ITabSetProps) => {
300
327
  style = layout.styleFont(style);
301
328
 
302
329
  return (
303
- <div ref={selfRef} style={style} className={cm(CLASSES.FLEXLAYOUT__TABSET)} onWheel={onMouseWheel}>
330
+ <div ref={selfRef} dir="ltr" style={style} className={cm(CLASSES.FLEXLAYOUT__TABSET)} onWheel={onMouseWheel}>
304
331
  {header}
305
332
  {tabStrip}
306
333
  </div>
307
334
  );
308
335
  };
336
+
337
+ /** @hidden @internal */
338
+ export function isAuxMouseEvent(event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) {
339
+ let auxEvent = false;
340
+ if (event.nativeEvent instanceof MouseEvent) {
341
+ if (event.nativeEvent.button !== 0 || event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) {
342
+ auxEvent = true;
343
+ }
344
+ }
345
+ return auxEvent;
346
+ }
347
+