flexlayout-react 0.5.15 → 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 (88) hide show
  1. package/ChangeLog.txt +26 -0
  2. package/README.md +121 -97
  3. package/declarations/DragDrop.d.ts +1 -0
  4. package/declarations/I18nLabel.d.ts +1 -0
  5. package/declarations/Rect.d.ts +4 -0
  6. package/declarations/Types.d.ts +9 -1
  7. package/declarations/model/Actions.d.ts +18 -11
  8. package/declarations/model/BorderNode.d.ts +2 -1
  9. package/declarations/model/IJsonModel.d.ts +10 -0
  10. package/declarations/model/Model.d.ts +1 -0
  11. package/declarations/model/TabNode.d.ts +1 -0
  12. package/declarations/model/TabSetNode.d.ts +1 -0
  13. package/declarations/view/Layout.d.ts +20 -6
  14. package/dist/flexlayout.js +20 -20
  15. package/dist/flexlayout_min.js +1 -1
  16. package/lib/DockLocation.js +25 -11
  17. package/lib/DockLocation.js.map +1 -1
  18. package/lib/DragDrop.js +19 -3
  19. package/lib/DragDrop.js.map +1 -1
  20. package/lib/I18nLabel.js +1 -0
  21. package/lib/I18nLabel.js.map +1 -1
  22. package/lib/PopupMenu.js +14 -9
  23. package/lib/PopupMenu.js.map +1 -1
  24. package/lib/Rect.js +3 -0
  25. package/lib/Rect.js.map +1 -1
  26. package/lib/Types.js +8 -0
  27. package/lib/Types.js.map +1 -1
  28. package/lib/model/Actions.js +20 -11
  29. package/lib/model/Actions.js.map +1 -1
  30. package/lib/model/BorderNode.js +61 -14
  31. package/lib/model/BorderNode.js.map +1 -1
  32. package/lib/model/BorderSet.js +33 -19
  33. package/lib/model/BorderSet.js.map +1 -1
  34. package/lib/model/Model.js +39 -1
  35. package/lib/model/Model.js.map +1 -1
  36. package/lib/model/RowNode.js +19 -5
  37. package/lib/model/RowNode.js.map +1 -1
  38. package/lib/model/TabNode.js +14 -0
  39. package/lib/model/TabNode.js.map +1 -1
  40. package/lib/model/TabSetNode.js +42 -19
  41. package/lib/model/TabSetNode.js.map +1 -1
  42. package/lib/view/BorderButton.js +14 -3
  43. package/lib/view/BorderButton.js.map +1 -1
  44. package/lib/view/BorderTabSet.js +15 -4
  45. package/lib/view/BorderTabSet.js.map +1 -1
  46. package/lib/view/Layout.js +206 -45
  47. package/lib/view/Layout.js.map +1 -1
  48. package/lib/view/Splitter.js +34 -3
  49. package/lib/view/Splitter.js.map +1 -1
  50. package/lib/view/TabButton.js +11 -2
  51. package/lib/view/TabButton.js.map +1 -1
  52. package/lib/view/TabFloating.js +23 -11
  53. package/lib/view/TabFloating.js.map +1 -1
  54. package/lib/view/TabSet.js +50 -17
  55. package/lib/view/TabSet.js.map +1 -1
  56. package/package.json +1 -1
  57. package/src/DockLocation.ts +30 -9
  58. package/src/DragDrop.ts +26 -3
  59. package/src/I18nLabel.ts +1 -0
  60. package/src/PopupMenu.tsx +28 -10
  61. package/src/Rect.ts +6 -2
  62. package/src/Types.ts +9 -0
  63. package/src/model/Actions.ts +21 -11
  64. package/src/model/BorderNode.ts +57 -15
  65. package/src/model/BorderSet.ts +32 -19
  66. package/src/model/IJsonModel.ts +10 -0
  67. package/src/model/Model.ts +43 -1
  68. package/src/model/RowNode.ts +8 -5
  69. package/src/model/TabNode.ts +16 -0
  70. package/src/model/TabSetNode.ts +43 -19
  71. package/src/view/BorderButton.tsx +22 -3
  72. package/src/view/BorderTabSet.tsx +21 -4
  73. package/src/view/Layout.tsx +263 -70
  74. package/src/view/Splitter.tsx +49 -3
  75. package/src/view/TabButton.tsx +17 -1
  76. package/src/view/TabFloating.tsx +36 -19
  77. package/src/view/TabSet.tsx +76 -16
  78. package/style/_base.scss +75 -44
  79. package/style/dark.css +90 -61
  80. package/style/dark.css.map +1 -1
  81. package/style/dark.scss +20 -20
  82. package/style/gray.css +90 -61
  83. package/style/gray.css.map +1 -1
  84. package/style/gray.scss +20 -20
  85. package/style/light.css +90 -61
  86. package/style/light.css.map +1 -1
  87. package/style/light.scss +18 -18
  88. package/yarn-error.log +0 -11828
@@ -8,6 +8,7 @@ class Actions {
8
8
  static ADD_NODE = "FlexLayout_AddNode";
9
9
  static MOVE_NODE = "FlexLayout_MoveNode";
10
10
  static DELETE_TAB = "FlexLayout_DeleteTab";
11
+ static DELETE_TABSET = "FlexLayout_DeleteTabset";
11
12
  static RENAME_TAB = "FlexLayout_RenameTab";
12
13
  static SELECT_TAB = "FlexLayout_SelectTab";
13
14
  static SET_ACTIVE_TABSET = "FlexLayout_SetActiveTabset";
@@ -26,7 +27,7 @@ class Actions {
26
27
  * @param location the location where the new tab will be added, one of the DockLocation enum values.
27
28
  * @param index for docking to the center this value is the index of the tab, use -1 to add to the end.
28
29
  * @param select (optional) whether to select the new tab, overriding autoSelectTab
29
- * @returns {{type: (string|string), json: *, toNode: *, location: (*|string), index: *, select?: boolean}}
30
+ * @returns {Action} the action
30
31
  */
31
32
  static addNode(json: any, toNodeId: string, location: DockLocation, index: number, select?: boolean): Action {
32
33
  return new Action(Actions.ADD_NODE, {
@@ -45,7 +46,7 @@ class Actions {
45
46
  * @param location the location where the moved node will be added, one of the DockLocation enum values.
46
47
  * @param index for docking to the center this value is the index of the tab, use -1 to add to the end.
47
48
  * @param select (optional) whether to select the moved tab(s) in new tabset, overriding autoSelectTab
48
- * @returns {{type: (string|string), fromNode: *, toNode: *, location: (*|string), index: *}}
49
+ * @returns {Action} the action
49
50
  */
50
51
  static moveNode(fromNodeId: string, toNodeId: string, location: DockLocation, index: number, select?: boolean): Action {
51
52
  return new Action(Actions.MOVE_NODE, {
@@ -59,18 +60,27 @@ class Actions {
59
60
 
60
61
  /**
61
62
  * Deletes a tab node from the layout
62
- * @param tabNodeId the id of the node to delete
63
- * @returns {{type: (string|string), node: *}}
63
+ * @param tabsetNodeId the id of the tab node to delete
64
+ * @returns {Action} the action
64
65
  */
65
66
  static deleteTab(tabNodeId: string): Action {
66
67
  return new Action(Actions.DELETE_TAB, { node: tabNodeId });
67
68
  }
68
69
 
70
+ /**
71
+ * Deletes a tabset node and all it's child tab nodes from the layout
72
+ * @param tabsetNodeId the id of the tabset node to delete
73
+ * @returns {Action} the action
74
+ */
75
+ static deleteTabset(tabsetNodeId: string): Action {
76
+ return new Action(Actions.DELETE_TABSET, { node: tabsetNodeId });
77
+ }
78
+
69
79
  /**
70
80
  * Change the given nodes tab text
71
81
  * @param tabNodeId the id of the node to rename
72
82
  * @param text the test of the tab
73
- * @returns {{type: (string|string), node: *, text: *}}
83
+ * @returns {Action} the action
74
84
  */
75
85
  static renameTab(tabNodeId: string, text: string): Action {
76
86
  return new Action(Actions.RENAME_TAB, { node: tabNodeId, text });
@@ -79,7 +89,7 @@ class Actions {
79
89
  /**
80
90
  * Selects the given tab in its parent tabset
81
91
  * @param tabNodeId the id of the node to set selected
82
- * @returns {{type: (string|string), tabNode: *}}
92
+ * @returns {Action} the action
83
93
  */
84
94
  static selectTab(tabNodeId: string): Action {
85
95
  return new Action(Actions.SELECT_TAB, { tabNode: tabNodeId });
@@ -88,7 +98,7 @@ class Actions {
88
98
  /**
89
99
  * Set the given tabset node as the active tabset
90
100
  * @param tabsetNodeId the id of the tabset node to set as active
91
- * @returns {{type: (string|string), tabsetNode: *}}
101
+ * @returns {Action} the action
92
102
  */
93
103
  static setActiveTabset(tabsetNodeId: string): Action {
94
104
  return new Action(Actions.SET_ACTIVE_TABSET, { tabsetNode: tabsetNodeId });
@@ -100,7 +110,7 @@ class Actions {
100
110
  * Actions.adjustSplit({node1: "1", weight1:30, pixelWidth1:300, node2: "2", weight2:70, pixelWidth2:700});
101
111
  *
102
112
  * @param splitSpec an object the defines the new split between two tabsets, see example below.
103
- * @returns {{type: (string|string), node1: *, weight1: *, pixelWidth1: *, node2: *, weight2: *, pixelWidth2: *}}
113
+ * @returns {Action} the action
104
114
  */
105
115
  static adjustSplit(splitSpec: { node1Id: string; weight1: number; pixelWidth1: number; node2Id: string; weight2: number; pixelWidth2: number }): Action {
106
116
  const node1 = splitSpec.node1Id;
@@ -123,7 +133,7 @@ class Actions {
123
133
  /**
124
134
  * Maximizes the given tabset
125
135
  * @param tabsetNodeId the id of the tabset to maximize
126
- * @returns {{type: (string|string), node: *}}
136
+ * @returns {Action} the action
127
137
  */
128
138
  static maximizeToggle(tabsetNodeId: string): Action {
129
139
  return new Action(Actions.MAXIMIZE_TOGGLE, { node: tabsetNodeId });
@@ -132,7 +142,7 @@ class Actions {
132
142
  /**
133
143
  * Updates the global model jsone attributes
134
144
  * @param attributes the json for the model attributes to update (merge into the existing attributes)
135
- * @returns {{type: (string|string), json: *}}
145
+ * @returns {Action} the action
136
146
  */
137
147
  static updateModelAttributes(attributes: any): Action {
138
148
  return new Action(Actions.UPDATE_MODEL_ATTRIBUTES, { json: attributes });
@@ -142,7 +152,7 @@ class Actions {
142
152
  * Updates the given nodes json attributes
143
153
  * @param nodeId the id of the node to update
144
154
  * @param attributes the json attributes to update (merge with the existing attributes)
145
- * @returns {{type: (string|string), node: *, json: *}}
155
+ * @returns {Action} the action
146
156
  */
147
157
  static updateNodeAttributes(nodeId: string, attributes: any): Action {
148
158
  return new Action(Actions.UPDATE_NODE_ATTRIBUTES, { node: nodeId, json: attributes });
@@ -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
@@ -55,6 +59,7 @@ export interface IGlobalAttributes {
55
59
  tabSetBorderInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
56
60
  tabSetClassNameHeader?: string;
57
61
  tabSetClassNameTabStrip?: string;
62
+ tabSetEnableClose?: boolean; // default: false
58
63
  tabSetEnableDeleteWhenEmpty?: boolean; // default: true
59
64
  tabSetEnableDivide?: boolean; // default: true
60
65
  tabSetEnableDrag?: boolean; // default: true
@@ -81,6 +86,7 @@ export interface ITabSetAttributes {
81
86
  classNameHeader?: string; // - inherited from global tabSetClassNameHeader
82
87
  classNameTabStrip?: string; // - inherited from global tabSetClassNameTabStrip
83
88
  config?: any;
89
+ enableClose?: boolean; // default: false - inherited from global tabSetEnableClose
84
90
  enableDeleteWhenEmpty?: boolean; // default: true - inherited from global tabSetEnableDeleteWhenEmpty
85
91
  enableDivide?: boolean; // default: true - inherited from global tabSetEnableDivide
86
92
  enableDrag?: boolean; // default: true - inherited from global tabSetEnableDrag
@@ -102,6 +108,8 @@ export interface ITabSetAttributes {
102
108
  width?: number;
103
109
  }
104
110
  export interface ITabAttributes {
111
+ borderHeight?: number; // default: -1 - inherited from global tabBorderHeight
112
+ borderWidth?: number; // default: -1 - inherited from global tabBorderWidth
105
113
  className?: string; // - inherited from global tabClassName
106
114
  closeType?: ICloseType; // default: 1 - inherited from global tabCloseType
107
115
  component?: string;
@@ -112,6 +120,7 @@ export interface ITabAttributes {
112
120
  enableRename?: boolean; // default: true - inherited from global tabEnableRename
113
121
  enableRenderOnDemand?: boolean; // default: true - inherited from global tabEnableRenderOnDemand
114
122
  floating?: boolean; // default: false
123
+ helpText?: string;
115
124
  icon?: string; // - inherited from global tabIcon
116
125
  id?: string;
117
126
  name?: string; // default: "[Unnamed Tab]"
@@ -123,6 +132,7 @@ export interface IBorderAttributes {
123
132
  barSize?: number; // default: 0 - inherited from global borderBarSize
124
133
  className?: string; // - inherited from global borderClassName
125
134
  config?: any;
135
+ enableAutoHide?: boolean; // default: false - inherited from global borderEnableAutoHide
126
136
  enableDrop?: boolean; // default: true - inherited from global borderEnableDrop
127
137
  minSize?: number; // default: 0 - inherited from global borderMinSize
128
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);
@@ -76,6 +79,7 @@ class Model {
76
79
  attributeDefinitions.add("tabSetEnableDrag", true).setType(Attribute.BOOLEAN);
77
80
  attributeDefinitions.add("tabSetEnableDivide", true).setType(Attribute.BOOLEAN);
78
81
  attributeDefinitions.add("tabSetEnableMaximize", true).setType(Attribute.BOOLEAN);
82
+ attributeDefinitions.add("tabSetEnableClose", false).setType(Attribute.BOOLEAN);
79
83
  attributeDefinitions.add("tabSetAutoSelectTab", true).setType(Attribute.BOOLEAN);
80
84
  attributeDefinitions.add("tabSetClassNameTabStrip", undefined).setType(Attribute.STRING);
81
85
  attributeDefinitions.add("tabSetClassNameHeader", undefined).setType(Attribute.STRING);
@@ -98,6 +102,8 @@ class Model {
98
102
  attributeDefinitions.add("borderAutoSelectTabWhenOpen", true).setType(Attribute.BOOLEAN);
99
103
  attributeDefinitions.add("borderAutoSelectTabWhenClosed", false).setType(Attribute.BOOLEAN);
100
104
  attributeDefinitions.add("borderClassName", undefined).setType(Attribute.STRING);
105
+ attributeDefinitions.add("borderEnableAutoHide", false).setType(Attribute.BOOLEAN);
106
+
101
107
  return attributeDefinitions;
102
108
  }
103
109
 
@@ -123,6 +129,9 @@ class Model {
123
129
  private _pointerFine: boolean;
124
130
  /** @hidden @internal */
125
131
  private _onCreateTabSet? : (tabNode?: TabNode) => ITabSetAttributes;
132
+ /** @hidden @internal */
133
+ private _showHiddenBorder: DockLocation;
134
+
126
135
 
127
136
  /**
128
137
  * 'private' constructor. Use the static method Model.fromJson(json) to create a model
@@ -134,6 +143,7 @@ class Model {
134
143
  this._idMap = {};
135
144
  this._borders = new BorderSet(this);
136
145
  this._pointerFine = true;
146
+ this._showHiddenBorder = DockLocation.CENTER;
137
147
  }
138
148
 
139
149
  /** @hidden @internal */
@@ -152,6 +162,16 @@ class Model {
152
162
  }
153
163
  }
154
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
+
155
175
  /** @hidden @internal */
156
176
  _setActiveTabset(tabsetNode: TabSetNode | undefined) {
157
177
  this._activeTabSet = tabsetNode;
@@ -253,11 +273,29 @@ class Model {
253
273
  case Actions.DELETE_TAB: {
254
274
  const node = this._idMap[action.data.node];
255
275
  if (node instanceof TabNode) {
256
- delete this._idMap[action.data.node];
257
276
  node._delete();
258
277
  }
259
278
  break;
260
279
  }
280
+ case Actions.DELETE_TABSET: {
281
+ const node = this._idMap[action.data.node];
282
+
283
+ if (node instanceof TabSetNode) {
284
+ // first delete all child tabs that are closeable
285
+ const children = [...node.getChildren()];
286
+ children.forEach((child, i) => {
287
+ if ((child as TabNode).isEnableClose()) {
288
+ (child as TabNode)._delete();
289
+ }
290
+ });
291
+
292
+ if (node.getChildren().length === 0) {
293
+ node._delete();
294
+ }
295
+ this._tidy();
296
+ }
297
+ break;
298
+ }
261
299
  case Actions.FLOAT_TAB: {
262
300
  const node = this._idMap[action.data.node];
263
301
  if (node instanceof TabNode) {
@@ -405,6 +443,10 @@ class Model {
405
443
  return splitterSize;
406
444
  }
407
445
 
446
+ getSplitterExtra() {
447
+ return this._attributes.splitterExtra as number;
448
+ }
449
+
408
450
  isEnableEdgeDock() {
409
451
  return this._attributes.enableEdgeDock as boolean;
410
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) {
@@ -26,6 +26,7 @@ class TabNode extends Node implements IDraggable {
26
26
  attributeDefinitions.add("id", undefined).setType(Attribute.STRING);
27
27
 
28
28
  attributeDefinitions.add("name", "[Unnamed Tab]").setType(Attribute.STRING);
29
+ attributeDefinitions.add("helpText", undefined).setType(Attribute.STRING);
29
30
  attributeDefinitions.add("component", undefined).setType(Attribute.STRING);
30
31
  attributeDefinitions.add("config", undefined).setType("any");
31
32
  attributeDefinitions.add("floating", false).setType(Attribute.BOOLEAN);
@@ -38,6 +39,8 @@ class TabNode extends Node implements IDraggable {
38
39
  attributeDefinitions.addInherited("icon", "tabIcon").setType(Attribute.STRING);
39
40
  attributeDefinitions.addInherited("enableRenderOnDemand", "tabEnableRenderOnDemand").setType(Attribute.BOOLEAN);
40
41
  attributeDefinitions.addInherited("enableFloat", "tabEnableFloat").setType(Attribute.BOOLEAN);
42
+ attributeDefinitions.addInherited("borderWidth", "tabBorderWidth").setType(Attribute.NUMBER);
43
+ attributeDefinitions.addInherited("borderHeight", "tabBorderHeight").setType(Attribute.NUMBER);
41
44
  return attributeDefinitions;
42
45
  }
43
46
 
@@ -89,6 +92,10 @@ class TabNode extends Node implements IDraggable {
89
92
  return this._getAttr("name") as string;
90
93
  }
91
94
 
95
+ getHelpText() {
96
+ return this._getAttr("helpText") as string | undefined;
97
+ }
98
+
92
99
  getComponent() {
93
100
  return this._getAttr("component") as string | undefined;
94
101
  }
@@ -195,7 +202,16 @@ class TabNode extends Node implements IDraggable {
195
202
  _setWindow(window: Window | undefined) {
196
203
  this._window = window;
197
204
  }
205
+
206
+ /** @hidden @internal */
207
+ _setBorderWidth(width: number) {
208
+ this._attributes.borderWidth = width;
209
+ }
198
210
 
211
+ /** @hidden @internal */
212
+ _setBorderHeight(height: number) {
213
+ this._attributes.borderHeight = height;
214
+ }
199
215
 
200
216
  /** @hidden @internal */
201
217
  static getAttributeDefinitions() {