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
package/src/DragDrop.ts CHANGED
@@ -23,6 +23,10 @@ class DragDrop {
23
23
  /** @hidden @internal */
24
24
  private _glass: HTMLDivElement | undefined;
25
25
  /** @hidden @internal */
26
+ private _defaultGlassCursor: string;
27
+ /** @hidden @internal */
28
+ private _glassCursorOverride: string | undefined;
29
+ /** @hidden @internal */
26
30
  private _manualGlassManagement: boolean = false;
27
31
  /** @hidden @internal */
28
32
  private _lastClick: number;
@@ -59,6 +63,8 @@ class DragDrop {
59
63
  this._glass.style.outline = "none";
60
64
  }
61
65
 
66
+ this._defaultGlassCursor = "default";
67
+
62
68
  this._onMouseMove = this._onMouseMove.bind(this);
63
69
  this._onMouseUp = this._onMouseUp.bind(this);
64
70
  this._onKeyPress = this._onKeyPress.bind(this);
@@ -111,9 +117,26 @@ class DragDrop {
111
117
  this._glassShowing = false;
112
118
  this._document = undefined;
113
119
  this._rootElement = undefined;
120
+ this.setGlassCursorOverride(undefined);
114
121
  }
115
122
  }
116
123
 
124
+ /** @hidden @internal */
125
+ _updateGlassCursor() {
126
+ this._glass!.style.cursor = this._glassCursorOverride ?? this._defaultGlassCursor;
127
+ }
128
+
129
+ /** @hidden @internal */
130
+ _setDefaultGlassCursor(cursor: string) {
131
+ this._defaultGlassCursor = cursor;
132
+ this._updateGlassCursor()
133
+ }
134
+
135
+ setGlassCursorOverride(cursor: string | undefined) {
136
+ this._glassCursorOverride = cursor;
137
+ this._updateGlassCursor()
138
+ }
139
+
117
140
  startDrag(
118
141
  event: Event | React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement> | React.DragEvent<Element> | undefined,
119
142
  fDragStart: ((pos: { clientX: number; clientY: number }) => boolean) | undefined,
@@ -154,14 +177,14 @@ class DragDrop {
154
177
  this._startX = posEvent.clientX;
155
178
  this._startY = posEvent.clientY;
156
179
  if (!window.matchMedia || window.matchMedia("(pointer: fine)").matches) {
157
- this._glass!.style.cursor = getComputedStyle(event.target as Element).cursor;
180
+ this._setDefaultGlassCursor(getComputedStyle(event.target as Element).cursor);
158
181
  }
159
182
  this._stopPropagation(event);
160
183
  this._preventDefault(event);
161
184
  } else {
162
185
  this._startX = 0;
163
186
  this._startY = 0;
164
- this._glass!.style.cursor = "default";
187
+ this._setDefaultGlassCursor("default");
165
188
  }
166
189
 
167
190
  this._dragging = false;
@@ -274,7 +297,7 @@ class DragDrop {
274
297
  if (!this._dragging && (Math.abs(this._startX - posEvent.clientX) > 5 || Math.abs(this._startY - posEvent.clientY) > 5)) {
275
298
  this._dragging = true;
276
299
  if (this._fDragStart) {
277
- this._glass!.style.cursor = "move";
300
+ this._setDefaultGlassCursor("move");
278
301
  this._dragging = this._fDragStart({ clientX: this._startX, clientY: this._startY });
279
302
  }
280
303
  }
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,8 +36,10 @@ 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",
42
+ FLEXLAYOUT__SPLITTER_EXTRA = "flexlayout__splitter_extra",
39
43
  FLEXLAYOUT__SPLITTER_ = "flexlayout__splitter_",
40
44
  FLEXLAYOUT__SPLITTER_BORDER = "flexlayout__splitter_border",
41
45
  FLEXLAYOUT__SPLITTER_DRAG = "flexlayout__splitter_drag",
@@ -77,4 +81,7 @@ export enum CLASSES {
77
81
  FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER = "flexlayout__tab_toolbar_sticky_buttons_container",
78
82
  FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE = "flexlayout__tab_toolbar_button-close",
79
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",
80
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
 
@@ -128,7 +130,19 @@ class BorderNode extends Node implements IDropTarget {
128
130
  }
129
131
 
130
132
  getSize() {
131
- return this._getAttr("size") as number;
133
+ const defaultSize = this._getAttr("size") as number;
134
+ const selected = this.getSelected();
135
+ if (selected === -1) {
136
+ return defaultSize;
137
+ } else {
138
+ const tabNode = this._children[selected] as TabNode;
139
+ const tabBorderSize = (this._location._orientation === Orientation.HORZ) ? tabNode._getAttr("borderWidth") : tabNode._getAttr("borderHeight");
140
+ if (tabBorderSize === -1) {
141
+ return defaultSize;
142
+ } else {
143
+ return tabBorderSize;
144
+ }
145
+ }
132
146
  }
133
147
 
134
148
  getMinSize() {
@@ -157,7 +171,7 @@ class BorderNode extends Node implements IDropTarget {
157
171
  * this.state.model.doAction(
158
172
  * FlexLayout.Actions.updateNodeAttributes(node.getId(), {config:myConfigObject}));
159
173
  */
160
- getConfig() {
174
+ getConfig() {
161
175
  return this._attributes.config;
162
176
  }
163
177
 
@@ -166,7 +180,19 @@ class BorderNode extends Node implements IDropTarget {
166
180
  }
167
181
 
168
182
  isShowing() {
169
- 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;
170
196
  }
171
197
 
172
198
  /** @hidden @internal */
@@ -176,7 +202,22 @@ class BorderNode extends Node implements IDropTarget {
176
202
 
177
203
  /** @hidden @internal */
178
204
  _setSize(pos: number) {
179
- this._attributes.size = pos;
205
+ const selected = this.getSelected();
206
+ if (selected === -1) {
207
+ this._attributes.size = pos;
208
+ } else {
209
+ const tabNode = this._children[selected] as TabNode;
210
+ const tabBorderSize = (this._location._orientation === Orientation.HORZ) ? tabNode._getAttr("borderWidth") : tabNode._getAttr("borderHeight");
211
+ if (tabBorderSize === -1) {
212
+ this._attributes.size = pos;
213
+ } else {
214
+ if (this._location._orientation === Orientation.HORZ) {
215
+ tabNode._setBorderWidth(pos);
216
+ } else {
217
+ tabNode._setBorderHeight(pos);
218
+ }
219
+ }
220
+ }
180
221
  }
181
222
 
182
223
  /** @hidden @internal */
@@ -269,18 +310,18 @@ class BorderNode extends Node implements IDropTarget {
269
310
  childCenter = childRect.x + childRect.width / 2;
270
311
  if (x >= pos && x < childCenter) {
271
312
  const outlineRect = new Rect(childRect.x - 2, childY, 3, childHeight);
272
- dropInfo = new DropInfo(this, outlineRect, dockLocation, i, "flexlayout__outline_rect");
313
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
273
314
  break;
274
315
  }
275
316
  pos = childCenter;
276
317
  }
277
318
  if (dropInfo == null) {
278
319
  const outlineRect = new Rect(childRect.getRight() - 2, childY, 3, childHeight);
279
- 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);
280
321
  }
281
322
  } else {
282
323
  const outlineRect = new Rect(this._tabHeaderRect!.x + 1, this._tabHeaderRect!.y + 2, 3, 18);
283
- dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, "flexlayout__outline_rect");
324
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
284
325
  }
285
326
  } else {
286
327
  if (this._children.length > 0) {
@@ -297,18 +338,18 @@ class BorderNode extends Node implements IDropTarget {
297
338
  childCenter = childRect.y + childRect.height / 2;
298
339
  if (y >= pos && y < childCenter) {
299
340
  const outlineRect = new Rect(childX, childRect.y - 2, childWidth, 3);
300
- dropInfo = new DropInfo(this, outlineRect, dockLocation, i, "flexlayout__outline_rect");
341
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
301
342
  break;
302
343
  }
303
344
  pos = childCenter;
304
345
  }
305
346
  if (dropInfo == null) {
306
347
  const outlineRect = new Rect(childX, childRect.getBottom() - 2, childWidth, 3);
307
- 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);
308
349
  }
309
350
  } else {
310
351
  const outlineRect = new Rect(this._tabHeaderRect!.x + 2, this._tabHeaderRect!.y + 1, 18, 3);
311
- dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, "flexlayout__outline_rect");
352
+ dropInfo = new DropInfo(this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
312
353
  }
313
354
  }
314
355
  if (!dragNode._canDockInto(dragNode, dropInfo)) {
@@ -316,7 +357,7 @@ class BorderNode extends Node implements IDropTarget {
316
357
  }
317
358
  } else if (this.getSelected() !== -1 && this._contentRect!.contains(x, y)) {
318
359
  const outlineRect = this._contentRect;
319
- dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, "flexlayout__outline_rect");
360
+ dropInfo = new DropInfo(this, outlineRect!, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT);
320
361
  if (!dragNode._canDockInto(dragNode, dropInfo)) {
321
362
  return undefined;
322
363
  }
@@ -370,18 +411,19 @@ class BorderNode extends Node implements IDropTarget {
370
411
  const minSize = useMinSize ? this.getMinSize() : 0;
371
412
  const outerRect = this._model._getOuterInnerRects().outer;
372
413
  const innerRect = this._model._getOuterInnerRects().inner;
414
+ const rootRow = this._model.getRoot();
373
415
  if (this._location === DockLocation.TOP) {
374
416
  pBounds[0] = outerRect.y + minSize;
375
- pBounds[1] = innerRect.getBottom() - splitter.getHeight();
417
+ pBounds[1] = Math.max(pBounds[0], innerRect.getBottom() - splitter.getHeight() - rootRow.getMinHeight());
376
418
  } else if (this._location === DockLocation.LEFT) {
377
419
  pBounds[0] = outerRect.x + minSize;
378
- pBounds[1] = innerRect.getRight() - splitter.getWidth();
420
+ pBounds[1] = Math.max(pBounds[0], innerRect.getRight() - splitter.getWidth() - rootRow.getMinWidth());
379
421
  } else if (this._location === DockLocation.BOTTOM) {
380
- pBounds[0] = innerRect.y;
381
422
  pBounds[1] = outerRect.getBottom() - splitter.getHeight() - minSize;
423
+ pBounds[0] = Math.min(pBounds[1], innerRect.y + rootRow.getMinHeight());
382
424
  } else if (this._location === DockLocation.RIGHT) {
383
- pBounds[0] = innerRect.x;
384
425
  pBounds[1] = outerRect.getRight() - splitter.getWidth() - minSize;
426
+ pBounds[0] = Math.min(pBounds[1], innerRect.x + rootRow.getMinWidth());
385
427
  }
386
428
  return pBounds;
387
429
  }
@@ -46,8 +46,9 @@ class BorderSet {
46
46
  /** @hidden @internal */
47
47
  _layoutBorder(outerInnerRects: { inner: Rect; outer: Rect }, metrics: ILayoutMetrics) {
48
48
  const rect = outerInnerRects.outer;
49
- const height = rect.height;
50
- const width = rect.width;
49
+ const rootRow = this._model.getRoot();
50
+ let height = Math.max(0, rect.height - rootRow.getMinHeight());
51
+ let width = Math.max(0, rect.width - rootRow.getMinWidth());
51
52
  let sumHeight = 0;
52
53
  let sumWidth = 0;
53
54
  let adjustableHeight = 0;
@@ -57,43 +58,55 @@ class BorderSet {
57
58
 
58
59
  // sum size of borders to see they will fit
59
60
  for (const border of showingBorders) {
60
- if (border.isShowing()) {
61
- border._setAdjustedSize(border.getSize());
62
- const visible = border.getSelected() !== -1;
63
- if (border.getLocation().getOrientation() === Orientation.HORZ) {
64
- sumWidth += border.getBorderBarSize() + this._model.getSplitterSize();
65
- if (visible) {
66
- sumWidth += border.getSize();
67
- adjustableWidth += border.getSize();
68
- }
69
- } else {
70
- sumHeight += border.getBorderBarSize() + this._model.getSplitterSize();
71
- if (visible) {
72
- sumHeight += border.getSize();
73
- adjustableHeight += border.getSize();
74
- }
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();
75
76
  }
76
77
  }
77
78
  }
78
79
 
79
80
  // adjust border sizes if too large
80
81
  let j = 0;
82
+ let adjusted = false;
81
83
  while ((sumWidth > width && adjustableWidth > 0) || (sumHeight > height && adjustableHeight > 0)) {
82
84
  const border = showingBorders[j];
83
85
  if (border.getSelected() !== -1) {
84
86
  // visible
85
87
  const size = border._getAdjustedSize();
86
- if (sumWidth > width && adjustableWidth > 0 && border.getLocation().getOrientation() === Orientation.HORZ && size > 0) {
88
+ if (sumWidth > width && adjustableWidth > 0 && border.getLocation().getOrientation() === Orientation.HORZ && size > 0
89
+ && size > border.getMinSize()) {
87
90
  border._setAdjustedSize(size - 1);
88
91
  sumWidth--;
89
92
  adjustableWidth--;
90
- } else if (sumHeight > height && adjustableHeight > 0 && border.getLocation().getOrientation() === Orientation.VERT && size > 0) {
93
+ adjusted = true;
94
+ } else if (sumHeight > height && adjustableHeight > 0 && border.getLocation().getOrientation() === Orientation.VERT && size > 0
95
+ && size > border.getMinSize()) {
91
96
  border._setAdjustedSize(size - 1);
92
97
  sumHeight--;
93
98
  adjustableHeight--;
99
+ adjusted = true;
94
100
  }
95
101
  }
96
102
  j = (j + 1) % showingBorders.length;
103
+ if (j===0) {
104
+ if (adjusted) {
105
+ adjusted = false;
106
+ } else {
107
+ break;
108
+ }
109
+ }
97
110
  }
98
111
 
99
112
  showingBorders.forEach((border) => {
@@ -35,13 +35,17 @@ 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
42
43
  marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
43
44
  rootOrientationVertical?: boolean; // default: false
45
+ splitterExtra?: number; // default: 0
44
46
  splitterSize?: number; // default: -1
47
+ tabBorderHeight?: number; // default: -1
48
+ tabBorderWidth?: number; // default: -1
45
49
  tabClassName?: string;
46
50
  tabCloseType?: ICloseType; // default: 1
47
51
  tabDragSpeed?: number; // default: 0.3
@@ -104,6 +108,8 @@ export interface ITabSetAttributes {
104
108
  width?: number;
105
109
  }
106
110
  export interface ITabAttributes {
111
+ borderHeight?: number; // default: -1 - inherited from global tabBorderHeight
112
+ borderWidth?: number; // default: -1 - inherited from global tabBorderWidth
107
113
  className?: string; // - inherited from global tabClassName
108
114
  closeType?: ICloseType; // default: 1 - inherited from global tabCloseType
109
115
  component?: string;
@@ -114,6 +120,7 @@ export interface ITabAttributes {
114
120
  enableRename?: boolean; // default: true - inherited from global tabEnableRename
115
121
  enableRenderOnDemand?: boolean; // default: true - inherited from global tabEnableRenderOnDemand
116
122
  floating?: boolean; // default: false
123
+ helpText?: string;
117
124
  icon?: string; // - inherited from global tabIcon
118
125
  id?: string;
119
126
  name?: string; // default: "[Unnamed Tab]"
@@ -125,6 +132,7 @@ export interface IBorderAttributes {
125
132
  barSize?: number; // default: 0 - inherited from global borderBarSize
126
133
  className?: string; // - inherited from global borderClassName
127
134
  config?: any;
135
+ enableAutoHide?: boolean; // default: false - inherited from global borderEnableAutoHide
128
136
  enableDrop?: boolean; // default: true - inherited from global borderEnableDrop
129
137
  minSize?: number; // default: 0 - inherited from global borderMinSize
130
138
  selected?: number; // default: -1
@@ -54,6 +54,7 @@ class Model {
54
54
  const attributeDefinitions = new AttributeDefinitions();
55
55
  // splitter
56
56
  attributeDefinitions.add("splitterSize", -1).setType(Attribute.NUMBER);
57
+ attributeDefinitions.add("splitterExtra", 0).setType(Attribute.NUMBER);
57
58
  attributeDefinitions.add("enableEdgeDock", true).setType(Attribute.BOOLEAN);
58
59
  attributeDefinitions.add("rootOrientationVertical", false).setType(Attribute.BOOLEAN);
59
60
  attributeDefinitions.add("marginInsets", { top: 0, right: 0, bottom: 0, left: 0 })
@@ -69,6 +70,8 @@ class Model {
69
70
  attributeDefinitions.add("tabIcon", undefined).setType(Attribute.STRING);
70
71
  attributeDefinitions.add("tabEnableRenderOnDemand", true).setType(Attribute.BOOLEAN);
71
72
  attributeDefinitions.add("tabDragSpeed", 0.3).setType(Attribute.NUMBER);
73
+ attributeDefinitions.add("tabBorderWidth", -1).setType(Attribute.NUMBER);
74
+ attributeDefinitions.add("tabBorderHeight", -1).setType(Attribute.NUMBER);
72
75
 
73
76
  // tabset
74
77
  attributeDefinitions.add("tabSetEnableDeleteWhenEmpty", true).setType(Attribute.BOOLEAN);
@@ -99,6 +102,8 @@ class Model {
99
102
  attributeDefinitions.add("borderAutoSelectTabWhenOpen", true).setType(Attribute.BOOLEAN);
100
103
  attributeDefinitions.add("borderAutoSelectTabWhenClosed", false).setType(Attribute.BOOLEAN);
101
104
  attributeDefinitions.add("borderClassName", undefined).setType(Attribute.STRING);
105
+ attributeDefinitions.add("borderEnableAutoHide", false).setType(Attribute.BOOLEAN);
106
+
102
107
  return attributeDefinitions;
103
108
  }
104
109
 
@@ -124,6 +129,9 @@ class Model {
124
129
  private _pointerFine: boolean;
125
130
  /** @hidden @internal */
126
131
  private _onCreateTabSet? : (tabNode?: TabNode) => ITabSetAttributes;
132
+ /** @hidden @internal */
133
+ private _showHiddenBorder: DockLocation;
134
+
127
135
 
128
136
  /**
129
137
  * 'private' constructor. Use the static method Model.fromJson(json) to create a model
@@ -135,6 +143,7 @@ class Model {
135
143
  this._idMap = {};
136
144
  this._borders = new BorderSet(this);
137
145
  this._pointerFine = true;
146
+ this._showHiddenBorder = DockLocation.CENTER;
138
147
  }
139
148
 
140
149
  /** @hidden @internal */
@@ -153,6 +162,16 @@ class Model {
153
162
  }
154
163
  }
155
164
 
165
+ /** @hidden @internal */
166
+ _getShowHiddenBorder() {
167
+ return this._showHiddenBorder;
168
+ }
169
+
170
+ /** @hidden @internal */
171
+ _setShowHiddenBorder(location: DockLocation) {
172
+ this._showHiddenBorder = location;
173
+ }
174
+
156
175
  /** @hidden @internal */
157
176
  _setActiveTabset(tabsetNode: TabSetNode | undefined) {
158
177
  this._activeTabSet = tabsetNode;
@@ -262,13 +281,17 @@ class Model {
262
281
  const node = this._idMap[action.data.node];
263
282
 
264
283
  if (node instanceof TabSetNode) {
265
- // first delete all child tabs
284
+ // first delete all child tabs that are closeable
266
285
  const children = [...node.getChildren()];
267
286
  children.forEach((child, i) => {
268
- (child as TabNode)._delete();
287
+ if ((child as TabNode).isEnableClose()) {
288
+ (child as TabNode)._delete();
289
+ }
269
290
  });
270
291
 
271
- node._delete();
292
+ if (node.getChildren().length === 0) {
293
+ node._delete();
294
+ }
272
295
  this._tidy();
273
296
  }
274
297
  break;
@@ -420,6 +443,10 @@ class Model {
420
443
  return splitterSize;
421
444
  }
422
445
 
446
+ getSplitterExtra() {
447
+ return this._attributes.splitterExtra as number;
448
+ }
449
+
423
450
  isEnableEdgeDock() {
424
451
  return this._attributes.enableEdgeDock as boolean;
425
452
  }
@@ -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) {