flexlayout-react 0.5.17 → 0.5.21

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 (74) hide show
  1. package/ChangeLog.txt +20 -0
  2. package/README.md +123 -104
  3. package/declarations/Rect.d.ts +4 -0
  4. package/declarations/Types.d.ts +7 -1
  5. package/declarations/model/BorderNode.d.ts +1 -0
  6. package/declarations/model/IJsonModel.d.ts +3 -0
  7. package/declarations/model/Model.d.ts +1 -0
  8. package/declarations/view/Layout.d.ts +11 -3
  9. package/declarations/view/Tab.d.ts +1 -1
  10. package/dist/flexlayout.js +17 -17
  11. package/dist/flexlayout_min.js +1 -1
  12. package/lib/PopupMenu.js +14 -9
  13. package/lib/PopupMenu.js.map +1 -1
  14. package/lib/Rect.js +3 -0
  15. package/lib/Rect.js.map +1 -1
  16. package/lib/Types.js +6 -0
  17. package/lib/Types.js.map +1 -1
  18. package/lib/model/BorderNode.js +22 -8
  19. package/lib/model/BorderNode.js.map +1 -1
  20. package/lib/model/BorderSet.js +15 -17
  21. package/lib/model/BorderSet.js.map +1 -1
  22. package/lib/model/Model.js +21 -3
  23. package/lib/model/Model.js.map +1 -1
  24. package/lib/model/RowNode.js +19 -5
  25. package/lib/model/RowNode.js.map +1 -1
  26. package/lib/model/TabSetNode.js +8 -4
  27. package/lib/model/TabSetNode.js.map +1 -1
  28. package/lib/view/BorderButton.js +17 -6
  29. package/lib/view/BorderButton.js.map +1 -1
  30. package/lib/view/BorderTabSet.js +17 -6
  31. package/lib/view/BorderTabSet.js.map +1 -1
  32. package/lib/view/FloatingWindow.js +13 -5
  33. package/lib/view/FloatingWindow.js.map +1 -1
  34. package/lib/view/Layout.js +205 -70
  35. package/lib/view/Layout.js.map +1 -1
  36. package/lib/view/Splitter.js +3 -3
  37. package/lib/view/Splitter.js.map +1 -1
  38. package/lib/view/Tab.js +18 -7
  39. package/lib/view/Tab.js.map +1 -1
  40. package/lib/view/TabButton.js +15 -8
  41. package/lib/view/TabButton.js.map +1 -1
  42. package/lib/view/TabFloating.js +29 -15
  43. package/lib/view/TabFloating.js.map +1 -1
  44. package/lib/view/TabSet.js +51 -25
  45. package/lib/view/TabSet.js.map +1 -1
  46. package/package.json +11 -6
  47. package/src/PopupMenu.tsx +32 -11
  48. package/src/Rect.ts +6 -2
  49. package/src/Types.ts +6 -0
  50. package/src/model/BorderNode.ts +22 -8
  51. package/src/model/BorderSet.ts +15 -17
  52. package/src/model/IJsonModel.ts +3 -0
  53. package/src/model/Model.ts +28 -3
  54. package/src/model/RowNode.ts +8 -5
  55. package/src/model/TabSetNode.ts +8 -4
  56. package/src/view/BorderButton.tsx +34 -6
  57. package/src/view/BorderTabSet.tsx +25 -5
  58. package/src/view/FloatingWindow.tsx +14 -6
  59. package/src/view/Layout.tsx +271 -92
  60. package/src/view/Splitter.tsx +4 -1
  61. package/src/view/Tab.tsx +22 -6
  62. package/src/view/TabButton.tsx +31 -11
  63. package/src/view/TabFloating.tsx +47 -23
  64. package/src/view/TabSet.tsx +72 -20
  65. package/style/_base.scss +72 -48
  66. package/style/dark.css +88 -66
  67. package/style/dark.css.map +1 -1
  68. package/style/dark.scss +20 -20
  69. package/style/gray.css +88 -66
  70. package/style/gray.css.map +1 -1
  71. package/style/gray.scss +20 -20
  72. package/style/light.css +88 -66
  73. package/style/light.css.map +1 -1
  74. package/style/light.scss +18 -18
package/src/PopupMenu.tsx CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import * as ReactDOM from "react-dom";
3
+ import { DragDrop } from ".";
3
4
  import TabNode from "./model/TabNode";
5
+ import { CLASSES } from "./Types";
4
6
 
5
7
  /** @hidden @internal */
6
8
  export function showPopup(
@@ -15,7 +17,7 @@ export function showPopup(
15
17
  const layoutRect = layoutDiv.getBoundingClientRect();
16
18
 
17
19
  const elm = currentDocument.createElement("div");
18
- elm.className = classNameMapper("flexlayout__popup_menu_container");
20
+ elm.className = classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU_CONTAINER);
19
21
  if (triggerRect.left < layoutRect.left + layoutRect.width / 2) {
20
22
  elm.style.left = triggerRect.left - layoutRect.left + "px";
21
23
  } else {
@@ -27,27 +29,37 @@ export function showPopup(
27
29
  } else {
28
30
  elm.style.bottom = layoutRect.bottom - triggerRect.bottom + "px";
29
31
  }
32
+ DragDrop.instance.addGlass(() => onHide());
33
+ DragDrop.instance.setGlassCursorOverride("default");
34
+
30
35
  layoutDiv.appendChild(elm);
31
36
 
32
37
  const onHide = () => {
38
+ DragDrop.instance.hideGlass();
33
39
  layoutDiv.removeChild(elm);
34
40
  ReactDOM.unmountComponentAtNode(elm);
35
- elm.removeEventListener("mouseup", onElementMouseUp);
36
- currentDocument.removeEventListener("mouseup", onDocMouseUp);
41
+ elm.removeEventListener("mousedown", onElementMouseDown);
42
+ currentDocument.removeEventListener("mousedown", onDocMouseDown);
37
43
  };
38
44
 
39
- const onElementMouseUp = (event: Event) => {
45
+ const onElementMouseDown = (event: Event) => {
40
46
  event.stopPropagation();
41
47
  };
42
48
 
43
- const onDocMouseUp = (event: Event) => {
49
+ const onDocMouseDown = (event: Event) => {
44
50
  onHide();
45
51
  };
46
52
 
47
- elm.addEventListener("mouseup", onElementMouseUp);
48
- currentDocument.addEventListener("mouseup", onDocMouseUp);
53
+ elm.addEventListener("mousedown", onElementMouseDown);
54
+ currentDocument.addEventListener("mousedown", onDocMouseDown);
49
55
 
50
- ReactDOM.render(<PopupMenu currentDocument={currentDocument} onSelect={onSelect} onHide={onHide} items={items} classNameMapper={classNameMapper} />, elm);
56
+ ReactDOM.render(<PopupMenu
57
+ currentDocument={currentDocument}
58
+ onSelect={onSelect}
59
+ onHide={onHide}
60
+ items={items}
61
+ classNameMapper={classNameMapper}
62
+ />, elm);
51
63
  }
52
64
 
53
65
  /** @hidden @internal */
@@ -69,11 +81,20 @@ const PopupMenu = (props: IPopupMenuProps) => {
69
81
  event.stopPropagation();
70
82
  };
71
83
 
72
- const itemElements = items.map((item) => (
73
- <div key={item.index} className={classNameMapper("flexlayout__popup_menu_item")} onClick={(event) => onItemClick(item, event)} title={item.node.getHelpText()}>
84
+ const itemElements = items.map((item, i) => (
85
+ <div key={item.index}
86
+ className={classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU_ITEM)}
87
+ data-layout-path={"/popup-menu/tb" + i}
88
+ onClick={(event) => onItemClick(item, event)}
89
+ title={item.node.getHelpText()}>
74
90
  {item.node._getRenderedName()}
75
91
  </div>
76
92
  ));
77
93
 
78
- return <div className={classNameMapper("flexlayout__popup_menu")}>{itemElements}</div>;
94
+ return (
95
+ <div className={classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU)}
96
+ data-layout-path="/popup-menu"
97
+ >
98
+ {itemElements}
99
+ </div>);
79
100
  };
package/src/Rect.ts CHANGED
@@ -18,8 +18,8 @@ class Rect {
18
18
  }
19
19
 
20
20
  static fromElement(element: Element) {
21
- let {x, y, width, height} = element.getBoundingClientRect();
22
- return new Rect(x, y, width, height);
21
+ let { x, y, width, height } = element.getBoundingClientRect();
22
+ return new Rect(x, y, width, height);
23
23
  }
24
24
 
25
25
  clone() {
@@ -42,6 +42,10 @@ class Rect {
42
42
  return this.x + this.width;
43
43
  }
44
44
 
45
+ getCenter() {
46
+ return { x: this.x + this.width / 2, y: this.y + this.height / 2 };
47
+ }
48
+
45
49
  positionElement(element: HTMLElement, position?: string) {
46
50
  this.styleWithPosition(element.style, position);
47
51
  }
package/src/Types.ts CHANGED
@@ -9,6 +9,8 @@ export enum CLASSES {
9
9
  FLEXLAYOUT__BORDER_BUTTON_TRAILING = "flexlayout__border_button_trailing",
10
10
  FLEXLAYOUT__BORDER_BUTTON__SELECTED = "flexlayout__border_button--selected",
11
11
  FLEXLAYOUT__BORDER_BUTTON__UNSELECTED = "flexlayout__border_button--unselected",
12
+ FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW = "flexlayout__border_toolbar_button_overflow",
13
+ FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW_ = "flexlayout__border_toolbar_button_overflow_",
12
14
 
13
15
  FLEXLAYOUT__BORDER_INNER = "flexlayout__border_inner",
14
16
  FLEXLAYOUT__BORDER_INNER_ = "flexlayout__border_inner_",
@@ -34,6 +36,7 @@ export enum CLASSES {
34
36
  FLEXLAYOUT__LAYOUT = "flexlayout__layout",
35
37
 
36
38
  FLEXLAYOUT__OUTLINE_RECT = "flexlayout__outline_rect",
39
+ FLEXLAYOUT__OUTLINE_RECT_EDGE = "flexlayout__outline_rect_edge",
37
40
 
38
41
  FLEXLAYOUT__SPLITTER = "flexlayout__splitter",
39
42
  FLEXLAYOUT__SPLITTER_EXTRA = "flexlayout__splitter_extra",
@@ -78,4 +81,7 @@ export enum CLASSES {
78
81
  FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER = "flexlayout__tab_toolbar_sticky_buttons_container",
79
82
  FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE = "flexlayout__tab_toolbar_button-close",
80
83
 
84
+ FLEXLAYOUT__POPUP_MENU_CONTAINER = "flexlayout__popup_menu_container",
85
+ FLEXLAYOUT__POPUP_MENU_ITEM = "flexlayout__popup_menu_item",
86
+ FLEXLAYOUT__POPUP_MENU = "flexlayout__popup_menu",
81
87
  }
@@ -4,6 +4,7 @@ import DockLocation from "../DockLocation";
4
4
  import DropInfo from "../DropInfo";
5
5
  import Orientation from "../Orientation";
6
6
  import Rect from "../Rect";
7
+ import { CLASSES } from "../Types";
7
8
  import IDraggable from "./IDraggable";
8
9
  import IDropTarget from "./IDropTarget";
9
10
  import { IJsonBorderNode } from "./IJsonModel";
@@ -50,6 +51,7 @@ class BorderNode extends Node implements IDropTarget {
50
51
  attributeDefinitions.addInherited("autoSelectTabWhenClosed", "borderAutoSelectTabWhenClosed").setType(Attribute.BOOLEAN);
51
52
  attributeDefinitions.addInherited("size", "borderSize").setType(Attribute.NUMBER);
52
53
  attributeDefinitions.addInherited("minSize", "borderMinSize").setType(Attribute.NUMBER);
54
+ attributeDefinitions.addInherited("enableAutoHide", "borderEnableAutoHide").setType(Attribute.BOOLEAN);
53
55
  return attributeDefinitions;
54
56
  }
55
57
 
@@ -178,7 +180,19 @@ class BorderNode extends Node implements IDropTarget {
178
180
  }
179
181
 
180
182
  isShowing() {
181
- return this._attributes.show as boolean;
183
+ const show = this._attributes.show as boolean;
184
+ if (show) {
185
+ if (this._model._getShowHiddenBorder() !== this._location && this.isAutoHide() && this._children.length === 0) {
186
+ return false;
187
+ }
188
+ return true;
189
+ } else {
190
+ return false;
191
+ }
192
+ }
193
+
194
+ isAutoHide() {
195
+ return this._getAttr("enableAutoHide") as boolean;
182
196
  }
183
197
 
184
198
  /** @hidden @internal */
@@ -296,18 +310,18 @@ class BorderNode extends Node implements IDropTarget {
296
310
  childCenter = childRect.x + childRect.width / 2;
297
311
  if (x >= pos && x < childCenter) {
298
312
  const outlineRect = new Rect(childRect.x - 2, childY, 3, childHeight);
299
- dropInfo = new DropInfo(this, outlineRect, dockLocation, i, "flexlayout__outline_rect");
313
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
300
314
  break;
301
315
  }
302
316
  pos = childCenter;
303
317
  }
304
318
  if (dropInfo == null) {
305
319
  const outlineRect = new Rect(childRect.getRight() - 2, childY, 3, childHeight);
306
- dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, "flexlayout__outline_rect");
320
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
307
321
  }
308
322
  } else {
309
323
  const outlineRect = new Rect(this._tabHeaderRect!.x + 1, this._tabHeaderRect!.y + 2, 3, 18);
310
- dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, "flexlayout__outline_rect");
324
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
311
325
  }
312
326
  } else {
313
327
  if (this._children.length > 0) {
@@ -324,18 +338,18 @@ class BorderNode extends Node implements IDropTarget {
324
338
  childCenter = childRect.y + childRect.height / 2;
325
339
  if (y >= pos && y < childCenter) {
326
340
  const outlineRect = new Rect(childX, childRect.y - 2, childWidth, 3);
327
- dropInfo = new DropInfo(this, outlineRect, dockLocation, i, "flexlayout__outline_rect");
341
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
328
342
  break;
329
343
  }
330
344
  pos = childCenter;
331
345
  }
332
346
  if (dropInfo == null) {
333
347
  const outlineRect = new Rect(childX, childRect.getBottom() - 2, childWidth, 3);
334
- dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, "flexlayout__outline_rect");
348
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
335
349
  }
336
350
  } else {
337
351
  const outlineRect = new Rect(this._tabHeaderRect!.x + 2, this._tabHeaderRect!.y + 1, 18, 3);
338
- dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, "flexlayout__outline_rect");
352
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
339
353
  }
340
354
  }
341
355
  if (!dragNode._canDockInto(dragNode, dropInfo)) {
@@ -343,7 +357,7 @@ class BorderNode extends Node implements IDropTarget {
343
357
  }
344
358
  } else if (this.getSelected() !== -1 && this._contentRect!.contains(x, y)) {
345
359
  const outlineRect = this._contentRect;
346
- dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, "flexlayout__outline_rect");
360
+ dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
347
361
  if (!dragNode._canDockInto(dragNode, dropInfo)) {
348
362
  return undefined;
349
363
  }
@@ -58,23 +58,21 @@ class BorderSet {
58
58
 
59
59
  // sum size of borders to see they will fit
60
60
  for (const border of showingBorders) {
61
- if (border.isShowing()) {
62
- border._setAdjustedSize(border.getSize());
63
- const visible = border.getSelected() !== -1;
64
- if (border.getLocation().getOrientation() === Orientation.HORZ) {
65
- sumWidth += border.getBorderBarSize() ;
66
- if (visible) {
67
- width -= this._model.getSplitterSize();
68
- sumWidth += border.getSize();
69
- adjustableWidth += border.getSize();
70
- }
71
- } else {
72
- sumHeight += border.getBorderBarSize();
73
- if (visible) {
74
- height -= this._model.getSplitterSize();
75
- sumHeight += border.getSize();
76
- adjustableHeight += border.getSize();
77
- }
61
+ border._setAdjustedSize(border.getSize());
62
+ const visible = border.getSelected() !== -1;
63
+ if (border.getLocation().getOrientation() === Orientation.HORZ) {
64
+ sumWidth += border.getBorderBarSize() ;
65
+ if (visible) {
66
+ width -= this._model.getSplitterSize();
67
+ sumWidth += border.getSize();
68
+ adjustableWidth += border.getSize();
69
+ }
70
+ } else {
71
+ sumHeight += border.getBorderBarSize();
72
+ if (visible) {
73
+ height -= this._model.getSplitterSize();
74
+ sumHeight += border.getSize();
75
+ adjustableHeight += border.getSize();
78
76
  }
79
77
  }
80
78
  }
@@ -35,10 +35,12 @@ export interface IGlobalAttributes {
35
35
  borderAutoSelectTabWhenOpen?: boolean; // default: true
36
36
  borderBarSize?: number; // default: 0
37
37
  borderClassName?: string;
38
+ borderEnableAutoHide?: boolean; // default: false
38
39
  borderEnableDrop?: boolean; // default: true
39
40
  borderMinSize?: number; // default: 0
40
41
  borderSize?: number; // default: 200
41
42
  enableEdgeDock?: boolean; // default: true
43
+ enableUseVisibility?: boolean; // default: false
42
44
  marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
43
45
  rootOrientationVertical?: boolean; // default: false
44
46
  splitterExtra?: number; // default: 0
@@ -131,6 +133,7 @@ export interface IBorderAttributes {
131
133
  barSize?: number; // default: 0 - inherited from global borderBarSize
132
134
  className?: string; // - inherited from global borderClassName
133
135
  config?: any;
136
+ enableAutoHide?: boolean; // default: false - inherited from global borderEnableAutoHide
134
137
  enableDrop?: boolean; // default: true - inherited from global borderEnableDrop
135
138
  minSize?: number; // default: 0 - inherited from global borderMinSize
136
139
  selected?: number; // default: -1
@@ -59,6 +59,7 @@ class Model {
59
59
  attributeDefinitions.add("rootOrientationVertical", false).setType(Attribute.BOOLEAN);
60
60
  attributeDefinitions.add("marginInsets", { top: 0, right: 0, bottom: 0, left: 0 })
61
61
  .setType("IInsets");
62
+ attributeDefinitions.add("enableUseVisibility", false).setType(Attribute.BOOLEAN);
62
63
 
63
64
  // tab
64
65
  attributeDefinitions.add("tabEnableClose", true).setType(Attribute.BOOLEAN);
@@ -102,6 +103,8 @@ class Model {
102
103
  attributeDefinitions.add("borderAutoSelectTabWhenOpen", true).setType(Attribute.BOOLEAN);
103
104
  attributeDefinitions.add("borderAutoSelectTabWhenClosed", false).setType(Attribute.BOOLEAN);
104
105
  attributeDefinitions.add("borderClassName", undefined).setType(Attribute.STRING);
106
+ attributeDefinitions.add("borderEnableAutoHide", false).setType(Attribute.BOOLEAN);
107
+
105
108
  return attributeDefinitions;
106
109
  }
107
110
 
@@ -127,6 +130,9 @@ class Model {
127
130
  private _pointerFine: boolean;
128
131
  /** @hidden @internal */
129
132
  private _onCreateTabSet? : (tabNode?: TabNode) => ITabSetAttributes;
133
+ /** @hidden @internal */
134
+ private _showHiddenBorder: DockLocation;
135
+
130
136
 
131
137
  /**
132
138
  * 'private' constructor. Use the static method Model.fromJson(json) to create a model
@@ -138,6 +144,7 @@ class Model {
138
144
  this._idMap = {};
139
145
  this._borders = new BorderSet(this);
140
146
  this._pointerFine = true;
147
+ this._showHiddenBorder = DockLocation.CENTER;
141
148
  }
142
149
 
143
150
  /** @hidden @internal */
@@ -156,6 +163,16 @@ class Model {
156
163
  }
157
164
  }
158
165
 
166
+ /** @hidden @internal */
167
+ _getShowHiddenBorder() {
168
+ return this._showHiddenBorder;
169
+ }
170
+
171
+ /** @hidden @internal */
172
+ _setShowHiddenBorder(location: DockLocation) {
173
+ this._showHiddenBorder = location;
174
+ }
175
+
159
176
  /** @hidden @internal */
160
177
  _setActiveTabset(tabsetNode: TabSetNode | undefined) {
161
178
  this._activeTabSet = tabsetNode;
@@ -185,6 +202,10 @@ class Model {
185
202
  return this._attributes.rootOrientationVertical as boolean;
186
203
  }
187
204
 
205
+ isUseVisibility() {
206
+ return this._attributes.enableUseVisibility as boolean;
207
+ }
208
+
188
209
  /**
189
210
  * Gets the
190
211
  * @returns {BorderSet|*}
@@ -265,13 +286,17 @@ class Model {
265
286
  const node = this._idMap[action.data.node];
266
287
 
267
288
  if (node instanceof TabSetNode) {
268
- // first delete all child tabs
289
+ // first delete all child tabs that are closeable
269
290
  const children = [...node.getChildren()];
270
291
  children.forEach((child, i) => {
271
- (child as TabNode)._delete();
292
+ if ((child as TabNode).isEnableClose()) {
293
+ (child as TabNode)._delete();
294
+ }
272
295
  });
273
296
 
274
- node._delete();
297
+ if (node.getChildren().length === 0) {
298
+ node._delete();
299
+ }
275
300
  this._tidy();
276
301
  }
277
302
  break;
@@ -5,6 +5,7 @@ import DockLocation from "../DockLocation";
5
5
  import DropInfo from "../DropInfo";
6
6
  import Orientation from "../Orientation";
7
7
  import Rect from "../Rect";
8
+ import { CLASSES } from "../Types";
8
9
  import BorderNode from "./BorderNode";
9
10
  import IDraggable from "./IDraggable";
10
11
  import IDropTarget from "./IDropTarget";
@@ -381,7 +382,9 @@ class RowNode extends Node implements IDropTarget {
381
382
  // add tabset into empty root
382
383
  if (this === this._model.getRoot() && this._children.length === 0) {
383
384
  const callback = this._model._getOnCreateTabSet();
384
- const child = new TabSetNode(this._model, callback ? callback() : {});
385
+ let attrs = callback ? callback() : {};
386
+ attrs = {...attrs, selected: -1};
387
+ const child = new TabSetNode(this._model, attrs);
385
388
  this._model._setActiveTabset(child);
386
389
  this._addChild(child);
387
390
  }
@@ -404,24 +407,24 @@ class RowNode extends Node implements IDropTarget {
404
407
  const dockLocation = DockLocation.LEFT;
405
408
  const outlineRect = dockLocation.getDockRect(this._rect);
406
409
  outlineRect.width = outlineRect.width / 2;
407
- dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, "flexlayout__outline_rect_edge");
410
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT_EDGE);
408
411
  } else if (x > this._rect.getRight() - margin && yy > h / 2 - half && yy < h / 2 + half) {
409
412
  const dockLocation = DockLocation.RIGHT;
410
413
  const outlineRect = dockLocation.getDockRect(this._rect);
411
414
  outlineRect.width = outlineRect.width / 2;
412
415
  outlineRect.x += outlineRect.width;
413
- dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, "flexlayout__outline_rect_edge");
416
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT_EDGE);
414
417
  } else if (y < this._rect.y + margin && xx > w / 2 - half && xx < w / 2 + half) {
415
418
  const dockLocation = DockLocation.TOP;
416
419
  const outlineRect = dockLocation.getDockRect(this._rect);
417
420
  outlineRect.height = outlineRect.height / 2;
418
- dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, "flexlayout__outline_rect_edge");
421
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT_EDGE);
419
422
  } else if (y > this._rect.getBottom() - margin && xx > w / 2 - half && xx < w / 2 + half) {
420
423
  const dockLocation = DockLocation.BOTTOM;
421
424
  const outlineRect = dockLocation.getDockRect(this._rect);
422
425
  outlineRect.height = outlineRect.height / 2;
423
426
  outlineRect.y += outlineRect.height;
424
- dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, "flexlayout__outline_rect_edge");
427
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT_EDGE);
425
428
  }
426
429
 
427
430
  if (dropInfo !== undefined) {
@@ -4,6 +4,7 @@ import DockLocation from "../DockLocation";
4
4
  import DropInfo from "../DropInfo";
5
5
  import Orientation from "../Orientation";
6
6
  import Rect from "../Rect";
7
+ import { CLASSES } from "../Types";
7
8
  import BorderNode from "./BorderNode";
8
9
  import IDraggable from "./IDraggable";
9
10
  import IDropTarget from "./IDropTarget";
@@ -27,6 +28,9 @@ class TabSetNode extends Node implements IDraggable, IDropTarget {
27
28
  newLayoutNode._addChild(child);
28
29
  });
29
30
  }
31
+ if (newLayoutNode._children.length === 0) {
32
+ newLayoutNode._setSelected(-1);
33
+ }
30
34
 
31
35
  if (json.maximized && json.maximized === true) {
32
36
  model._setMaximizedTabset(newLayoutNode);
@@ -268,11 +272,11 @@ class TabSetNode extends Node implements IDraggable, IDropTarget {
268
272
  if (dragNode === this) {
269
273
  const dockLocation = DockLocation.CENTER;
270
274
  const outlineRect = this._tabHeaderRect;
271
- dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, "flexlayout__outline_rect");
275
+ dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
272
276
  } else if (this._contentRect!.contains(x, y)) {
273
277
  const dockLocation = DockLocation.getLocation(this._contentRect!, x, y);
274
278
  const outlineRect = dockLocation.getDockRect(this._rect);
275
- dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, "flexlayout__outline_rect");
279
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
276
280
  } else if (this._tabHeaderRect != null && this._tabHeaderRect.contains(x, y)) {
277
281
  let r: Rect;
278
282
  let yy: number;
@@ -296,7 +300,7 @@ class TabSetNode extends Node implements IDraggable, IDropTarget {
296
300
  if (x >= p && x < childCenter) {
297
301
  const dockLocation = DockLocation.CENTER;
298
302
  const outlineRect = new Rect(r.x - 2, yy, 3, h);
299
- dropInfo = new DropInfo(this, outlineRect, dockLocation, i, "flexlayout__outline_rect");
303
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
300
304
  break;
301
305
  }
302
306
  p = childCenter;
@@ -305,7 +309,7 @@ class TabSetNode extends Node implements IDraggable, IDropTarget {
305
309
  if (dropInfo == null) {
306
310
  const dockLocation = DockLocation.CENTER;
307
311
  const outlineRect = new Rect(r.getRight() - 2, yy, 3, h);
308
- dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, "flexlayout__outline_rect");
312
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, this._children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
309
313
  }
310
314
  }
311
315
 
@@ -6,6 +6,7 @@ import Rect from "../Rect";
6
6
  import { IIcons, ILayoutCallbacks, ITitleObject } from "./Layout";
7
7
  import { ICloseType } from "../model/ICloseType";
8
8
  import { CLASSES } from "../Types";
9
+ import { isAuxMouseEvent } from "./TabSet";
9
10
 
10
11
  /** @hidden @internal */
11
12
  export interface IBorderButtonProps {
@@ -16,16 +17,29 @@ export interface IBorderButtonProps {
16
17
  iconFactory?: (node: TabNode) => React.ReactNode | undefined;
17
18
  titleFactory?: (node: TabNode) => React.ReactNode | undefined;
18
19
  icons?: IIcons;
20
+ path: string;
19
21
  }
20
22
 
21
23
  /** @hidden @internal */
22
24
  export const BorderButton = (props: IBorderButtonProps) => {
23
- const { layout, node, selected, border, iconFactory, titleFactory, icons } = props;
25
+ const { layout, node, selected, border, iconFactory, titleFactory, icons, path } = props;
24
26
  const selfRef = React.useRef<HTMLDivElement | null>(null);
25
27
 
26
28
  const onMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
27
- const message = layout.i18nName(I18nLabel.Move_Tab, node.getName());
28
- props.layout.dragStart(event, message, node, node.isEnableDrag(), onClick, (event2: Event) => undefined);
29
+ if (!isAuxMouseEvent(event)) {
30
+ const message = layout.i18nName(I18nLabel.Move_Tab, node.getName());
31
+ props.layout.dragStart(event, message, node, node.isEnableDrag(), onClick, (event2: Event) => undefined);
32
+ }
33
+ };
34
+
35
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
36
+ if (isAuxMouseEvent(event)) {
37
+ layout.auxMouseClick(node, event);
38
+ }
39
+ };
40
+
41
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
42
+ layout.showContextMenu(node, event);
29
43
  };
30
44
 
31
45
  const onClick = () => {
@@ -105,7 +119,7 @@ export const BorderButton = (props: IBorderButtonProps) => {
105
119
  }
106
120
  }
107
121
 
108
- if (typeof leadingContent === undefined && typeof node.getIcon() !== undefined) {
122
+ if (leadingContent === undefined && node.getIcon() !== undefined) {
109
123
  leadingContent = <img src={node.getIcon()} alt="leadingContent" />;
110
124
  }
111
125
 
@@ -122,14 +136,28 @@ export const BorderButton = (props: IBorderButtonProps) => {
122
136
  if (node.isEnableClose()) {
123
137
  const closeTitle = layout.i18nName(I18nLabel.Close_Tab);
124
138
  buttons.push(
125
- <div key="close" title={closeTitle} className={cm(CLASSES.FLEXLAYOUT__BORDER_BUTTON_TRAILING)} onMouseDown={onCloseMouseDown} onClick={onClose} onTouchStart={onCloseMouseDown}>
139
+ <div
140
+ key="close"
141
+ data-layout-path={path + "/button/close"}
142
+ title={closeTitle}
143
+ className={cm(CLASSES.FLEXLAYOUT__BORDER_BUTTON_TRAILING)}
144
+ onMouseDown={onCloseMouseDown}
145
+ onClick={onClose}
146
+ onTouchStart={onCloseMouseDown}>
126
147
  {icons?.close}
127
148
  </div>
128
149
  );
129
150
  }
130
151
 
131
152
  return (
132
- <div ref={selfRef} style={{}} className={classNames} onMouseDown={onMouseDown} onTouchStart={onMouseDown} title={node.getHelpText()}>
153
+ <div ref={selfRef} style={{}} className={classNames}
154
+ data-layout-path={path}
155
+ onMouseDown={onMouseDown}
156
+ onClick={onAuxMouseClick}
157
+ onAuxClick={onAuxMouseClick}
158
+ onContextMenu={onContextMenu}
159
+ onTouchStart={onMouseDown}
160
+ title={node.getHelpText()}>
133
161
  {leading}
134
162
  {content}
135
163
  {buttons}
@@ -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 {
@@ -18,11 +19,12 @@ export interface IBorderTabSetProps {
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 BorderTabSet = (props: IBorderTabSetProps) => {
25
- const { border, layout, iconFactory, titleFactory, icons } = props;
27
+ const { border, 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);
@@ -30,13 +32,24 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
30
32
 
31
33
  const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel } = useTabOverflow(border, Orientation.flip(border.getOrientation()), toolbarRef, stickyButtonsRef);
32
34
 
35
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
36
+ if (isAuxMouseEvent(event)) {
37
+ layout.auxMouseClick(border, event);
38
+ }
39
+ };
40
+
41
+ const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
42
+ layout.showContextMenu(border, event);
43
+ };
44
+
33
45
  const onInterceptMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.MouseEvent<HTMLButtonElement, MouseEvent> | React.TouchEvent<HTMLButtonElement>) => {
34
46
  event.stopPropagation();
35
47
  };
36
48
 
37
- const onOverflowClick = () => {
49
+ const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
38
50
  const element = overflowbuttonRef.current!;
39
51
  showPopup(layout.getRootDiv(), element, hiddenTabs, onOverflowItemSelect, layout.getClassName);
52
+ event.stopPropagation();
40
53
  };
41
54
 
42
55
  const onOverflowItemSelect = (item: { node: TabNode; index: number }) => {
@@ -44,11 +57,12 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
44
57
  userControlledLeft.current = false;
45
58
  };
46
59
 
47
- const onFloatTab = () => {
60
+ const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
48
61
  const selectedTabNode = border.getChildren()[border.getSelected()] as TabNode;
49
62
  if (selectedTabNode !== undefined) {
50
63
  layout.doAction(Actions.floatTab(selectedTabNode.getId()));
51
64
  }
65
+ event.stopPropagation();
52
66
  };
53
67
 
54
68
  const cm = layout.getClassName;
@@ -65,6 +79,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
65
79
  layout={layout}
66
80
  border={border.getLocation().getName()}
67
81
  node={child}
82
+ path={path + "/tb" + i}
68
83
  key={child.getId()}
69
84
  selected={isSelected}
70
85
  iconFactory={iconFactory}
@@ -97,7 +112,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
97
112
  <button
98
113
  key="overflowbutton"
99
114
  ref={overflowbuttonRef}
100
- className={cm("flexlayout__border_toolbar_button_overflow") + " " + cm("flexlayout__border_toolbar_button_overflow_" + border.getLocation().getName())}
115
+ className={cm(CLASSES.FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_OVERFLOW_ + border.getLocation().getName())}
101
116
  title={overflowTitle}
102
117
  onClick={onOverflowClick}
103
118
  onMouseDown={onInterceptMouseDown}
@@ -145,7 +160,12 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
145
160
  }
146
161
 
147
162
  return (
148
- <div ref={selfRef} style={style} className={borderClasses} onWheel={onMouseWheel}>
163
+ <div ref={selfRef} dir="ltr" style={style} className={borderClasses}
164
+ data-layout-path={path}
165
+ onClick={onAuxMouseClick}
166
+ onAuxClick={onAuxMouseClick}
167
+ onContextMenu={onContextMenu}
168
+ onWheel={onMouseWheel}>
149
169
  <div style={{ height: borderHeight }} className={cm(CLASSES.FLEXLAYOUT__BORDER_INNER) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_INNER_ + border.getLocation().getName())}>
150
170
  <div style={innerStyle} className={cm(CLASSES.FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER) + " " + cm(CLASSES.FLEXLAYOUT__BORDER_INNER_TAB_CONTAINER_ + border.getLocation().getName())}>
151
171
  {tabs}