flexlayout-react 0.7.15 → 0.8.0

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 (252) hide show
  1. package/ChangeLog.txt +23 -0
  2. package/README.md +157 -330
  3. package/Screenshot_light.png +0 -0
  4. package/Screenshot_rounded.png +0 -0
  5. package/declarations/Attribute.d.ts +1 -1
  6. package/declarations/AttributeDefinitions.d.ts +1 -1
  7. package/declarations/DockLocation.d.ts +12 -12
  8. package/declarations/DropInfo.d.ts +12 -12
  9. package/declarations/I18nLabel.d.ts +12 -14
  10. package/declarations/Orientation.d.ts +7 -7
  11. package/declarations/PopupMenu.d.ts +1 -1
  12. package/declarations/Rect.d.ts +41 -28
  13. package/declarations/Types.d.ts +95 -79
  14. package/declarations/examples/demo/Utils.d.ts +4 -0
  15. package/declarations/index.d.ts +21 -22
  16. package/declarations/model/Action.d.ts +5 -5
  17. package/declarations/model/Actions.d.ts +127 -110
  18. package/declarations/model/BorderNode.d.ts +30 -34
  19. package/declarations/model/BorderSet.d.ts +3 -4
  20. package/declarations/model/ICloseType.d.ts +5 -5
  21. package/declarations/model/IDraggable.d.ts +2 -2
  22. package/declarations/model/IDropTarget.d.ts +2 -2
  23. package/declarations/model/IJsonModel.d.ts +811 -149
  24. package/declarations/model/LayoutWindow.d.ts +28 -0
  25. package/declarations/model/Model.d.ts +91 -86
  26. package/declarations/model/Node.d.ts +17 -17
  27. package/declarations/model/RowNode.d.ts +10 -11
  28. package/declarations/model/TabNode.d.ts +44 -37
  29. package/declarations/model/TabSetNode.d.ts +44 -41
  30. package/declarations/model/Utils.d.ts +1 -1
  31. package/declarations/model/WindowLayout.d.ts +24 -0
  32. package/declarations/src/Attribute.d.ts +1 -0
  33. package/declarations/src/AttributeDefinitions.d.ts +1 -0
  34. package/declarations/src/DockLocation.d.ts +12 -0
  35. package/declarations/src/DropInfo.d.ts +12 -0
  36. package/declarations/src/I18nLabel.d.ts +10 -0
  37. package/declarations/src/Orientation.d.ts +7 -0
  38. package/declarations/src/PopupMenu.d.ts +1 -0
  39. package/declarations/src/Rect.d.ts +31 -0
  40. package/declarations/src/Types.d.ts +92 -0
  41. package/declarations/src/index.d.ts +20 -0
  42. package/declarations/src/model/Action.d.ts +5 -0
  43. package/declarations/src/model/Actions.d.ts +110 -0
  44. package/declarations/src/model/BorderNode.d.ts +28 -0
  45. package/declarations/src/model/BorderSet.d.ts +3 -0
  46. package/declarations/src/model/ICloseType.d.ts +5 -0
  47. package/declarations/src/model/IDraggable.d.ts +2 -0
  48. package/declarations/src/model/IDropTarget.d.ts +2 -0
  49. package/declarations/src/model/IJsonModel.d.ts +153 -0
  50. package/declarations/src/model/Model.d.ts +98 -0
  51. package/declarations/src/model/Node.d.ts +16 -0
  52. package/declarations/src/model/RowNode.d.ts +11 -0
  53. package/declarations/src/model/TabNode.d.ts +36 -0
  54. package/declarations/src/model/TabSetNode.d.ts +37 -0
  55. package/declarations/src/model/Utils.d.ts +1 -0
  56. package/declarations/src/view/BorderButton.d.ts +1 -0
  57. package/declarations/src/view/BorderTab.d.ts +2 -0
  58. package/declarations/src/view/BorderTabSet.d.ts +1 -0
  59. package/declarations/src/view/DragContainer.d.ts +1 -0
  60. package/declarations/src/view/ErrorBoundary.d.ts +1 -0
  61. package/declarations/src/view/FloatingWindow.d.ts +1 -0
  62. package/declarations/src/view/Icons.d.ts +7 -0
  63. package/declarations/src/view/Layout.d.ts +113 -0
  64. package/declarations/src/view/Overlay.d.ts +1 -0
  65. package/declarations/src/view/PopupMenu.d.ts +1 -0
  66. package/declarations/src/view/Row.d.ts +1 -0
  67. package/declarations/src/view/Splitter.d.ts +1 -0
  68. package/declarations/src/view/Tab.d.ts +1 -0
  69. package/declarations/src/view/TabButton.d.ts +1 -0
  70. package/declarations/src/view/TabButtonStamp.d.ts +1 -0
  71. package/declarations/src/view/TabOverflowHook.d.ts +1 -0
  72. package/declarations/src/view/TabSet.d.ts +1 -0
  73. package/declarations/src/view/Utils.d.ts +4 -0
  74. package/declarations/view/BorderButton.d.ts +1 -1
  75. package/declarations/view/BorderTab.d.ts +2 -0
  76. package/declarations/view/BorderTabSet.d.ts +1 -1
  77. package/declarations/view/DragContainer.d.ts +1 -0
  78. package/declarations/view/ErrorBoundary.d.ts +1 -1
  79. package/declarations/view/ExtendedResizeObserver.d.ts +23 -0
  80. package/declarations/view/FloatingWindow.d.ts +1 -1
  81. package/declarations/view/Icons.d.ts +8 -7
  82. package/declarations/view/Layout.d.ts +139 -161
  83. package/declarations/view/Overlay.d.ts +1 -0
  84. package/declarations/view/PopoutWindow.d.ts +1 -0
  85. package/declarations/view/PopupMenu.d.ts +1 -0
  86. package/declarations/view/Row.d.ts +1 -0
  87. package/declarations/view/SizeTracker.d.ts +10 -0
  88. package/declarations/view/Splitter.d.ts +1 -1
  89. package/declarations/view/Tab.d.ts +1 -1
  90. package/declarations/view/TabButton.d.ts +1 -1
  91. package/declarations/view/TabButtonStamp.d.ts +1 -1
  92. package/declarations/view/TabOverflowHook.d.ts +1 -1
  93. package/declarations/view/TabSet.d.ts +1 -1
  94. package/declarations/view/Utils.d.ts +11 -1
  95. package/dist/bundles/demo.js +232052 -0
  96. package/dist/bundles/demo.js.map +1 -0
  97. package/dist/flexlayout.js +122 -92
  98. package/dist/flexlayout_min.js +1 -1
  99. package/lib/Attribute.js +42 -31
  100. package/lib/Attribute.js.map +1 -1
  101. package/lib/AttributeDefinitions.js +131 -108
  102. package/lib/AttributeDefinitions.js.map +1 -1
  103. package/lib/DockLocation.js +120 -124
  104. package/lib/DockLocation.js.map +1 -1
  105. package/lib/DropInfo.js +9 -13
  106. package/lib/DropInfo.js.map +1 -1
  107. package/lib/I18nLabel.js +13 -18
  108. package/lib/I18nLabel.js.map +1 -1
  109. package/lib/Orientation.js +22 -26
  110. package/lib/Orientation.js.map +1 -1
  111. package/lib/Rect.js +104 -72
  112. package/lib/Rect.js.map +1 -1
  113. package/lib/Types.js +96 -83
  114. package/lib/Types.js.map +1 -1
  115. package/lib/index.js +21 -38
  116. package/lib/index.js.map +1 -1
  117. package/lib/model/Action.js +6 -10
  118. package/lib/model/Action.js.map +1 -1
  119. package/lib/model/Actions.js +169 -155
  120. package/lib/model/Actions.js.map +1 -1
  121. package/lib/model/BorderNode.js +385 -406
  122. package/lib/model/BorderNode.js.map +1 -1
  123. package/lib/model/BorderSet.js +66 -121
  124. package/lib/model/BorderSet.js.map +1 -1
  125. package/lib/model/ICloseType.js +6 -9
  126. package/lib/model/ICloseType.js.map +1 -1
  127. package/lib/model/IDraggable.js +1 -2
  128. package/lib/model/IDropTarget.js +1 -2
  129. package/lib/model/IJsonModel.js +1 -2
  130. package/lib/model/LayoutWindow.js +83 -0
  131. package/lib/model/LayoutWindow.js.map +1 -0
  132. package/lib/model/Model.js +614 -496
  133. package/lib/model/Model.js.map +1 -1
  134. package/lib/model/Node.js +217 -228
  135. package/lib/model/Node.js.map +1 -1
  136. package/lib/model/RowNode.js +491 -504
  137. package/lib/model/RowNode.js.map +1 -1
  138. package/lib/model/TabNode.js +289 -184
  139. package/lib/model/TabNode.js.map +1 -1
  140. package/lib/model/TabSetNode.js +457 -446
  141. package/lib/model/TabSetNode.js.map +1 -1
  142. package/lib/model/Utils.js +47 -82
  143. package/lib/model/Utils.js.map +1 -1
  144. package/lib/view/BorderButton.js +124 -138
  145. package/lib/view/BorderButton.js.map +1 -1
  146. package/lib/view/BorderTab.js +47 -0
  147. package/lib/view/BorderTab.js.map +1 -0
  148. package/lib/view/BorderTabSet.js +134 -128
  149. package/lib/view/BorderTabSet.js.map +1 -1
  150. package/lib/view/DragContainer.js +16 -0
  151. package/lib/view/DragContainer.js.map +1 -0
  152. package/lib/view/ErrorBoundary.js +23 -27
  153. package/lib/view/ErrorBoundary.js.map +1 -1
  154. package/lib/view/Icons.js +40 -45
  155. package/lib/view/Icons.js.map +1 -1
  156. package/lib/view/Layout.js +918 -907
  157. package/lib/view/Layout.js.map +1 -1
  158. package/lib/view/Overlay.js +9 -0
  159. package/lib/view/Overlay.js.map +1 -0
  160. package/lib/view/PopoutWindow.js +129 -0
  161. package/lib/view/PopoutWindow.js.map +1 -0
  162. package/lib/view/PopupMenu.js +71 -0
  163. package/lib/view/PopupMenu.js.map +1 -0
  164. package/lib/view/Row.js +45 -0
  165. package/lib/view/Row.js.map +1 -0
  166. package/lib/view/SizeTracker.js +11 -0
  167. package/lib/view/SizeTracker.js.map +1 -0
  168. package/lib/view/Splitter.js +191 -147
  169. package/lib/view/Splitter.js.map +1 -1
  170. package/lib/view/Tab.js +86 -60
  171. package/lib/view/Tab.js.map +1 -1
  172. package/lib/view/TabButton.js +122 -135
  173. package/lib/view/TabButton.js.map +1 -1
  174. package/lib/view/TabButtonStamp.js +16 -21
  175. package/lib/view/TabButtonStamp.js.map +1 -1
  176. package/lib/view/TabOverflowHook.js +150 -149
  177. package/lib/view/TabOverflowHook.js.map +1 -1
  178. package/lib/view/TabSet.js +267 -234
  179. package/lib/view/TabSet.js.map +1 -1
  180. package/lib/view/Utils.js +126 -68
  181. package/lib/view/Utils.js.map +1 -1
  182. package/package.json +36 -30
  183. package/src/Attribute.ts +23 -0
  184. package/src/AttributeDefinitions.ts +38 -15
  185. package/src/DockLocation.ts +13 -13
  186. package/src/I18nLabel.ts +7 -9
  187. package/src/Rect.ts +53 -1
  188. package/src/Types.ts +16 -0
  189. package/src/index.ts +1 -2
  190. package/src/model/Actions.ts +49 -29
  191. package/src/model/BorderNode.ts +208 -214
  192. package/src/model/BorderSet.ts +42 -91
  193. package/src/model/IJsonModel.ts +883 -103
  194. package/src/model/LayoutWindow.ts +121 -0
  195. package/src/model/Model.ts +488 -366
  196. package/src/model/Node.ts +98 -111
  197. package/src/model/RowNode.ts +323 -319
  198. package/src/model/TabNode.ts +294 -110
  199. package/src/model/TabSetNode.ts +300 -242
  200. package/src/model/Utils.ts +6 -32
  201. package/src/view/BorderButton.tsx +32 -52
  202. package/src/view/BorderTab.tsx +70 -0
  203. package/src/view/BorderTabSet.tsx +64 -52
  204. package/src/view/DragContainer.tsx +32 -0
  205. package/src/view/Icons.tsx +6 -0
  206. package/src/view/Layout.tsx +1051 -1046
  207. package/src/view/Overlay.tsx +22 -0
  208. package/src/view/PopoutWindow.tsx +152 -0
  209. package/src/{PopupMenu.tsx → view/PopupMenu.tsx} +36 -31
  210. package/src/view/Row.tsx +68 -0
  211. package/src/view/SizeTracker.tsx +20 -0
  212. package/src/view/Splitter.tsx +167 -112
  213. package/src/view/Tab.tsx +76 -42
  214. package/src/view/TabButton.tsx +36 -55
  215. package/src/view/TabButtonStamp.tsx +5 -9
  216. package/src/view/TabOverflowHook.tsx +14 -9
  217. package/src/view/TabSet.tsx +217 -176
  218. package/src/view/Utils.tsx +119 -39
  219. package/style/_base.scss +140 -34
  220. package/style/dark.css +685 -580
  221. package/style/dark.css.map +1 -1
  222. package/style/dark.scss +3 -1
  223. package/style/gray.css +668 -563
  224. package/style/gray.css.map +1 -1
  225. package/style/gray.scss +2 -0
  226. package/style/light.css +669 -564
  227. package/style/light.css.map +1 -1
  228. package/style/light.scss +4 -2
  229. package/style/rounded.css +697 -0
  230. package/style/rounded.css.map +1 -0
  231. package/style/rounded.scss +194 -0
  232. package/style/underline.css +690 -585
  233. package/style/underline.css.map +1 -1
  234. package/style/underline.scss +2 -0
  235. package/cypress.config.ts +0 -16
  236. package/lib/DragDrop.js +0 -316
  237. package/lib/DragDrop.js.map +0 -1
  238. package/lib/PopupMenu.js +0 -68
  239. package/lib/PopupMenu.js.map +0 -1
  240. package/lib/model/SplitterNode.js +0 -72
  241. package/lib/model/SplitterNode.js.map +0 -1
  242. package/lib/view/FloatingWindow.js +0 -123
  243. package/lib/view/FloatingWindow.js.map +0 -1
  244. package/lib/view/FloatingWindowTab.js +0 -19
  245. package/lib/view/FloatingWindowTab.js.map +0 -1
  246. package/lib/view/TabFloating.js +0 -66
  247. package/lib/view/TabFloating.js.map +0 -1
  248. package/src/DragDrop.ts +0 -392
  249. package/src/model/SplitterNode.ts +0 -78
  250. package/src/view/FloatingWindow.tsx +0 -140
  251. package/src/view/FloatingWindowTab.tsx +0 -29
  252. package/src/view/TabFloating.tsx +0 -101
@@ -3,35 +3,52 @@ import { I18nLabel } from "../I18nLabel";
3
3
  import { Actions } from "../model/Actions";
4
4
  import { TabNode } from "../model/TabNode";
5
5
  import { TabSetNode } from "../model/TabSetNode";
6
- import { showPopup } from "../PopupMenu";
7
- import { IIcons, ILayoutCallbacks, ITabSetRenderValues, ITitleObject } from "./Layout";
6
+ import { showPopup } from "./PopupMenu";
7
+ import { LayoutInternal, ITabSetRenderValues } from "./Layout";
8
8
  import { TabButton } from "./TabButton";
9
9
  import { useTabOverflow } from "./TabOverflowHook";
10
10
  import { Orientation } from "../Orientation";
11
11
  import { CLASSES } from "../Types";
12
- import { hideElement, isAuxMouseEvent } from "./Utils";
12
+ import { isAuxMouseEvent } from "./Utils";
13
+ import { createPortal } from "react-dom";
14
+ import { Rect } from "../Rect";
13
15
 
14
16
  /** @internal */
15
17
  export interface ITabSetProps {
16
- layout: ILayoutCallbacks;
18
+ layout: LayoutInternal;
17
19
  node: TabSetNode;
18
- iconFactory?: (node: TabNode) => (React.ReactNode | undefined);
19
- titleFactory?: (node: TabNode) => (ITitleObject | React.ReactNode | undefined);
20
- icons: IIcons;
21
- editingTab?: TabNode;
22
- path?: string;
23
20
  }
24
21
 
25
22
  /** @internal */
26
23
  export const TabSet = (props: ITabSetProps) => {
27
- const { node, layout, iconFactory, titleFactory, icons, path } = props;
24
+ const { node, layout } = props;
28
25
 
29
- const toolbarRef = React.useRef<HTMLDivElement | null>(null);
26
+ const tabStripRef = React.useRef<HTMLDivElement | null>(null);
27
+ const tabStripInnerRef = React.useRef<HTMLDivElement | null>(null);
28
+ const contentRef = React.useRef<HTMLDivElement | null>(null);
29
+ const buttonBarRef = React.useRef<HTMLDivElement | null>(null);
30
30
  const overflowbuttonRef = React.useRef<HTMLButtonElement | null>(null);
31
- const tabbarInnerRef = React.useRef<HTMLDivElement | null>(null);
32
31
  const stickyButtonsRef = React.useRef<HTMLDivElement | null>(null);
33
32
 
34
- const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel, tabsTruncated } = useTabOverflow(node, Orientation.HORZ, toolbarRef, stickyButtonsRef);
33
+ const icons = layout.getIcons();
34
+
35
+ // must use useEffect (rather than useLayoutEffect) otherwise contentrect not set correctly (has height 0 when changing theme in demo)
36
+ React.useEffect(() => {
37
+ node.setRect(layout.getBoundingClientRect(selfRef.current!));
38
+
39
+ if (tabStripRef.current) {
40
+ node.setTabStripRect(layout.getBoundingClientRect(tabStripRef.current!));
41
+ }
42
+
43
+ const newContentRect = Rect.getContentRect(contentRef.current!).relativeTo(layout.getDomRect()!);
44
+ if (!node.getContentRect().equals(newContentRect)) {
45
+ node.setContentRect(newContentRect);
46
+ layout.redrawInternal("tabset content rect " + newContentRect);
47
+ }
48
+ });
49
+
50
+ // this must be after the useEffect, so the node rect is already set (else window popin will not position tabs correctly)
51
+ const { selfRef, position, userControlledLeft, hiddenTabs, onMouseWheel, tabsTruncated } = useTabOverflow(node, Orientation.HORZ, buttonBarRef, stickyButtonsRef);
35
52
 
36
53
  const onOverflowClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
37
54
  const callback = layout.getShowOverflowMenu();
@@ -43,9 +60,7 @@ export const TabSet = (props: ITabSetProps) => {
43
60
  element,
44
61
  hiddenTabs,
45
62
  onOverflowItemSelect,
46
- layout,
47
- iconFactory,
48
- titleFactory,
63
+ layout
49
64
  );
50
65
  }
51
66
  event.stopPropagation();
@@ -56,7 +71,16 @@ export const TabSet = (props: ITabSetProps) => {
56
71
  userControlledLeft.current = false;
57
72
  };
58
73
 
59
- const onMouseDown = (event: React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement>) => {
74
+ const onDragStart = (event: React.DragEvent<HTMLElement>) => {
75
+ if (!layout.getEditingTab()) {
76
+ event.stopPropagation();
77
+ layout.setDragNode(event.nativeEvent, node as TabSetNode);
78
+ } else {
79
+ event.preventDefault();
80
+ }
81
+ };
82
+
83
+ const onPointerDown = (event: React.PointerEvent<HTMLElement>) => {
60
84
  if (!isAuxMouseEvent(event)) {
61
85
  let name = node.getName();
62
86
  if (name === undefined) {
@@ -64,29 +88,21 @@ export const TabSet = (props: ITabSetProps) => {
64
88
  } else {
65
89
  name = ": " + name;
66
90
  }
67
- layout.doAction(Actions.setActiveTabset(node.getId()));
68
- if (!layout.getEditingTab()) {
69
- const message = layout.i18nName(I18nLabel.Move_Tabset, name);
70
- if (node.getModel().getMaximizedTabset() !== undefined) {
71
- layout.dragStart(event, message, node, false, (event2: Event) => undefined, onDoubleClick);
72
- } else {
73
- layout.dragStart(event, message, node, node.isEnableDrag(), (event2: Event) => undefined, onDoubleClick);
74
- }
75
- }
91
+ layout.doAction(Actions.setActiveTabset(node.getId(), layout.getWindowId()));
76
92
  }
77
93
  };
78
94
 
79
- const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
95
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
80
96
  if (isAuxMouseEvent(event)) {
81
97
  layout.auxMouseClick(node, event);
82
98
  }
83
99
  };
84
100
 
85
- const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
101
+ const onContextMenu = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
86
102
  layout.showContextMenu(node, event);
87
103
  };
88
104
 
89
- const onInterceptMouseDown = (event: React.MouseEvent | React.TouchEvent) => {
105
+ const onInterceptPointerDown = (event: React.PointerEvent) => {
90
106
  event.stopPropagation();
91
107
  };
92
108
 
@@ -107,33 +123,31 @@ export const TabSet = (props: ITabSetProps) => {
107
123
  event.stopPropagation();
108
124
  };
109
125
 
110
- const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
126
+ const onPopoutTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
111
127
  if (selectedTabNode !== undefined) {
112
- layout.doAction(Actions.floatTab(selectedTabNode.getId()));
128
+ layout.doAction(Actions.popoutTab(selectedTabNode.getId()));
129
+ // layout.doAction(Actions.popoutTabset(node.getId()));
113
130
  }
114
131
  event.stopPropagation();
115
132
  };
116
133
 
117
- const onDoubleClick = (event: Event) => {
134
+ const onDoubleClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
118
135
  if (node.canMaximize()) {
119
136
  layout.maximize(node);
120
137
  }
121
138
  };
122
139
 
123
140
  // Start Render
141
+
124
142
  const cm = layout.getClassName;
125
143
 
126
144
  // tabbar inner can get shifted left via tab rename, this resets scrollleft to 0
127
- if (tabbarInnerRef.current !== null && tabbarInnerRef.current!.scrollLeft !== 0) {
128
- tabbarInnerRef.current.scrollLeft = 0;
145
+ if (tabStripInnerRef.current !== null && tabStripInnerRef.current!.scrollLeft !== 0) {
146
+ tabStripInnerRef.current.scrollLeft = 0;
129
147
  }
130
148
 
131
149
  const selectedTabNode: TabNode = node.getSelectedNode() as TabNode;
132
- let style = node._styleWithPosition();
133
-
134
- if (node.getModel().getMaximizedTabset() !== undefined && !node.isMaximized()) {
135
- hideElement(style, node.getModel().isUseVisibility())
136
- }
150
+ const path = node.getPath();
137
151
 
138
152
  const tabs = [];
139
153
  if (node.isEnableTabStrip()) {
@@ -147,30 +161,23 @@ export const TabSet = (props: ITabSetProps) => {
147
161
  path={path + "/tb" + i}
148
162
  key={child.getId()}
149
163
  selected={isSelected}
150
- iconFactory={iconFactory}
151
- titleFactory={titleFactory}
152
- icons={icons}
153
164
  />);
154
- if (i < node.getChildren().length-1) {
155
- tabs.push(
156
- <div key={"divider" + i} className={cm(CLASSES.FLEXLAYOUT__TABSET_TAB_DIVIDER)}></div>
157
- );
158
- }
165
+ if (i < node.getChildren().length - 1) {
166
+ tabs.push(
167
+ <div key={"divider" + i} className={cm(CLASSES.FLEXLAYOUT__TABSET_TAB_DIVIDER)}></div>
168
+ );
169
+ }
159
170
  }
160
171
  }
161
172
 
162
- const showHeader = node.getName() !== undefined;
163
173
  let stickyButtons: React.ReactNode[] = [];
164
174
  let buttons: React.ReactNode[] = [];
165
- let headerButtons: React.ReactNode[] = [];
166
175
 
167
176
  // allow customization of header contents and buttons
168
- const renderState : ITabSetRenderValues = { headerContent: node.getName(), stickyButtons, buttons, headerButtons, overflowPosition: undefined };
177
+ const renderState: ITabSetRenderValues = { stickyButtons, buttons, overflowPosition: undefined };
169
178
  layout.customizeTabSet(node, renderState);
170
- const headerContent = renderState.headerContent;
171
179
  stickyButtons = renderState.stickyButtons;
172
180
  buttons = renderState.buttons;
173
- headerButtons = renderState.headerButtons;
174
181
 
175
182
  const isTabStretch = node.isEnableSingleTabStretch() && node.getChildren().length === 1;
176
183
  const showClose = (isTabStretch && ((node.getChildren()[0] as TabNode).isEnableClose())) || node.isEnableClose();
@@ -178,16 +185,15 @@ export const TabSet = (props: ITabSetProps) => {
178
185
  if (renderState.overflowPosition === undefined) {
179
186
  renderState.overflowPosition = stickyButtons.length;
180
187
  }
181
-
188
+
182
189
  if (stickyButtons.length > 0) {
183
- if (tabsTruncated || isTabStretch) {
190
+ if (!node.isEnableTabWrap() && (tabsTruncated || isTabStretch)) {
184
191
  buttons = [...stickyButtons, ...buttons];
185
192
  } else {
186
193
  tabs.push(<div
187
194
  ref={stickyButtonsRef}
188
195
  key="sticky_buttons_container"
189
- onMouseDown={onInterceptMouseDown}
190
- onTouchStart={onInterceptMouseDown}
196
+ onPointerDown={onInterceptPointerDown}
191
197
  onDragStart={(e) => { e.preventDefault() }}
192
198
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER)}
193
199
  >
@@ -195,64 +201,67 @@ export const TabSet = (props: ITabSetProps) => {
195
201
  </div>);
196
202
  }
197
203
  }
198
-
199
- if (hiddenTabs.length > 0) {
200
- const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip);
201
- let overflowContent;
202
- if (typeof icons.more === "function") {
203
- overflowContent = icons.more(node, hiddenTabs);
204
- } else {
205
- overflowContent = (<>
206
- {icons.more}
207
- <div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length}</div>
208
- </>);
204
+
205
+ if (!node.isEnableTabWrap()) {
206
+ if (hiddenTabs.length > 0) {
207
+ const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip);
208
+ let overflowContent;
209
+ if (typeof icons.more === "function") {
210
+ overflowContent = icons.more(node, hiddenTabs);
211
+ } else {
212
+ overflowContent = (<>
213
+ {icons.more}
214
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length}</div>
215
+ </>);
216
+ }
217
+ buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,
218
+ <button
219
+ key="overflowbutton"
220
+ data-layout-path={path + "/button/overflow"}
221
+
222
+ ref={overflowbuttonRef}
223
+ className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
224
+ title={overflowTitle}
225
+ onClick={onOverflowClick}
226
+ onPointerDown={onInterceptPointerDown}
227
+ >
228
+ {overflowContent}
229
+ </button>
230
+ );
209
231
  }
210
- buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,
211
- <button
212
- key="overflowbutton"
213
- data-layout-path={path + "/button/overflow"}
214
-
215
- ref={overflowbuttonRef}
216
- className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
217
- title={overflowTitle}
218
- onClick={onOverflowClick}
219
- onMouseDown={onInterceptMouseDown}
220
- onTouchStart={onInterceptMouseDown}
221
- >
222
- {overflowContent}
223
- </button>
224
- );
225
232
  }
226
233
 
227
- if (selectedTabNode !== undefined && layout.isSupportsPopout() && selectedTabNode.isEnableFloat() && !selectedTabNode.isFloating()) {
228
- const floatTitle = layout.i18nName(I18nLabel.Float_Tab);
234
+ if (selectedTabNode !== undefined &&
235
+ layout.isSupportsPopout() &&
236
+ selectedTabNode.isEnablePopout() &&
237
+ selectedTabNode.isEnablePopoutIcon() ) {
238
+
239
+ const popoutTitle = layout.i18nName(I18nLabel.Popout_Tab);
229
240
  buttons.push(
230
241
  <button
231
- key="float"
232
- data-layout-path={path + "/button/float"}
233
- title={floatTitle}
242
+ key="popout"
243
+ data-layout-path={path + "/button/popout"}
244
+ title={popoutTitle}
234
245
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_FLOAT)}
235
- onClick={onFloatTab}
236
- onMouseDown={onInterceptMouseDown}
237
- onTouchStart={onInterceptMouseDown}
246
+ onClick={onPopoutTab}
247
+ onPointerDown={onInterceptPointerDown}
238
248
  >
239
249
  {(typeof icons.popout === "function") ? icons.popout(selectedTabNode) : icons.popout}
240
250
  </button>
241
251
  );
242
252
  }
253
+
243
254
  if (node.canMaximize()) {
244
255
  const minTitle = layout.i18nName(I18nLabel.Restore);
245
256
  const maxTitle = layout.i18nName(I18nLabel.Maximize);
246
- const btns = showHeader ? headerButtons : buttons;
247
- btns.push(
257
+ buttons.push(
248
258
  <button
249
259
  key="max"
250
260
  data-layout-path={path + "/button/max"}
251
261
  title={node.isMaximized() ? minTitle : maxTitle}
252
262
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_ + (node.isMaximized() ? "max" : "min"))}
253
263
  onClick={onMaximizeToggle}
254
- onMouseDown={onInterceptMouseDown}
255
- onTouchStart={onInterceptMouseDown}
264
+ onPointerDown={onInterceptPointerDown}
256
265
  >
257
266
  {node.isMaximized() ?
258
267
  (typeof icons.restore === "function") ? icons.restore(node) : icons.restore :
@@ -263,34 +272,44 @@ export const TabSet = (props: ITabSetProps) => {
263
272
 
264
273
  if (!node.isMaximized() && showClose) {
265
274
  const title = isTabStretch ? layout.i18nName(I18nLabel.Close_Tab) : layout.i18nName(I18nLabel.Close_Tabset);
266
- const btns = showHeader ? headerButtons : buttons;
267
- btns.push(
275
+ buttons.push(
268
276
  <button
269
277
  key="close"
270
278
  data-layout-path={path + "/button/close"}
271
279
  title={title}
272
280
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE)}
273
281
  onClick={isTabStretch ? onCloseTab : onClose}
274
- onMouseDown={onInterceptMouseDown}
275
- onTouchStart={onInterceptMouseDown}
282
+ onPointerDown={onInterceptPointerDown}
276
283
  >
277
284
  {(typeof icons.closeTabset === "function") ? icons.closeTabset(node) : icons.closeTabset}
278
285
  </button>
279
286
  );
280
287
  }
281
288
 
282
- const toolbar = (
283
- <div key="toolbar" ref={toolbarRef}
289
+ if (node.isActive() && node.isEnableActiveIcon()) {
290
+ const title = layout.i18nName(I18nLabel.Active_Tabset);
291
+ buttons.push(
292
+ <div
293
+ key="active"
294
+ data-layout-path={path + "/button/active"}
295
+ title={title}
296
+ className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_ICON) }
297
+ >
298
+ {(typeof icons.activeTabset === "function") ? icons.activeTabset(node) : icons.activeTabset}
299
+ </div>
300
+ );
301
+ }
302
+
303
+ const buttonbar = (
304
+ <div key="buttonbar" ref={buttonBarRef}
284
305
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR)}
285
- onMouseDown={onInterceptMouseDown}
286
- onTouchStart={onInterceptMouseDown}
306
+ onPointerDown={onInterceptPointerDown}
287
307
  onDragStart={(e) => { e.preventDefault() }}
288
308
  >
289
309
  {buttons}
290
310
  </div>
291
311
  );
292
312
 
293
- let header;
294
313
  let tabStrip;
295
314
 
296
315
  let tabStripClasses = cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_OUTER);
@@ -299,111 +318,133 @@ export const TabSet = (props: ITabSetProps) => {
299
318
  }
300
319
  tabStripClasses += " " + CLASSES.FLEXLAYOUT__TABSET_TABBAR_OUTER_ + node.getTabLocation();
301
320
 
302
- if (node.isActive() && !showHeader) {
321
+ if (node.isActive()) {
303
322
  tabStripClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_SELECTED);
304
323
  }
305
324
 
306
- if (node.isMaximized() && !showHeader) {
325
+ if (node.isMaximized()) {
307
326
  tabStripClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_MAXIMIZED);
308
327
  }
309
328
 
310
329
  if (isTabStretch) {
311
- const tabNode = node.getChildren()[0] as TabNode;
330
+ const tabNode = node.getChildren()[0] as TabNode;
312
331
  if (tabNode.getTabSetClassName() !== undefined) {
313
332
  tabStripClasses += " " + tabNode.getTabSetClassName();
314
333
  }
315
334
  }
316
335
 
317
- if (showHeader) {
318
-
319
- const headerToolbar = (
320
- <div key="toolbar" ref={toolbarRef}
321
- className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR)}
322
- onMouseDown={onInterceptMouseDown}
323
- onTouchStart={onInterceptMouseDown}
324
- onDragStart={(e) => { e.preventDefault() }}
325
- >
326
- {headerButtons}
327
- </div>
328
- );
329
-
330
- let tabHeaderClasses = cm(CLASSES.FLEXLAYOUT__TABSET_HEADER);
331
- if (node.isActive()) {
332
- tabHeaderClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_SELECTED);
333
- }
334
- if (node.isMaximized()) {
335
- tabHeaderClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_MAXIMIZED);
336
- }
337
- if (node.getClassNameHeader() !== undefined) {
338
- tabHeaderClasses += " " + node.getClassNameHeader();
339
- }
340
-
341
- header = (
342
- <div className={tabHeaderClasses} style={{ height: node.getHeaderHeight() + "px" }}
343
- data-layout-path={path + "/header"}
344
- onMouseDown={onMouseDown}
345
- onContextMenu={onContextMenu}
346
- onClick={onAuxMouseClick}
347
- onAuxClick={onAuxMouseClick}
348
- onTouchStart={onMouseDown}>
349
- <div className={cm(CLASSES.FLEXLAYOUT__TABSET_HEADER_CONTENT)}>{headerContent}</div>
350
- {headerToolbar}
351
- </div>
352
- );
353
- }
354
-
355
- const tabStripStyle: { [key: string]: string } = { height: node.getTabStripHeight() + "px" };
356
- tabStrip = (
357
- <div className={tabStripClasses} style={tabStripStyle}
358
- data-layout-path={path + "/tabstrip"}
359
- onMouseDown={onMouseDown}
360
- onContextMenu={onContextMenu}
361
- onClick={onAuxMouseClick}
362
- onAuxClick={onAuxMouseClick}
363
- onTouchStart={onMouseDown}>
364
- <div ref={tabbarInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
365
- <div
366
- style={{ left: position, width: (isTabStretch? "100%": "10000px")}}
367
- className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER_ + node.getTabLocation())}
336
+ if (node.isEnableTabWrap()) {
337
+ if (node.isEnableTabStrip()) {
338
+ tabStrip = (
339
+ <div className={tabStripClasses}
340
+ style={{ flexWrap: "wrap", gap:"1px", marginTop:"2px" }}
341
+ ref={tabStripRef}
342
+ data-layout-path={path + "/tabstrip"}
343
+ onPointerDown={onPointerDown}
344
+ onDoubleClick={onDoubleClick}
345
+ onContextMenu={onContextMenu}
346
+ onClick={onAuxMouseClick}
347
+ onAuxClick={onAuxMouseClick}
348
+ draggable={true}
349
+ onDragStart={onDragStart}
368
350
  >
369
351
  {tabs}
352
+ <div style={{ flexGrow: 1 }} />
353
+ {buttonbar}
370
354
  </div>
371
- </div>
372
- {toolbar}
373
- </div>
374
- );
375
-
376
- style = layout.styleFont(style);
355
+ );
356
+ }
357
+ } else {
358
+ if (node.isEnableTabStrip()) {
359
+ tabStrip = (
360
+ <div className={tabStripClasses}
361
+ ref={tabStripRef}
362
+ data-layout-path={path + "/tabstrip"}
363
+ onPointerDown={onPointerDown}
364
+ onDoubleClick={onDoubleClick}
365
+ onContextMenu={onContextMenu}
366
+ onClick={onAuxMouseClick}
367
+ onAuxClick={onAuxMouseClick}
368
+ draggable={true}
369
+ onWheel={onMouseWheel}
370
+ onDragStart={onDragStart}
371
+ >
372
+ <div ref={tabStripInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
373
+ <div
374
+ style={{ left: position, width: (isTabStretch ? "100%" : "10000px") }}
375
+ className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER_ + node.getTabLocation())}
376
+ >
377
+ {tabs}
378
+ </div>
379
+ </div>
380
+ {buttonbar}
381
+ </div>
382
+ );
383
+ }
384
+ }
377
385
 
378
- var placeHolder: React.ReactNode = undefined;
386
+ var emptyTabset: React.ReactNode;
379
387
  if (node.getChildren().length === 0) {
380
388
  const placeHolderCallback = layout.getTabSetPlaceHolderCallback();
381
389
  if (placeHolderCallback) {
382
- placeHolder = placeHolderCallback(node);
390
+ emptyTabset = placeHolderCallback(node);
383
391
  }
384
392
  }
385
393
 
386
- const center = <div className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTENT)}>
387
- {placeHolder}
394
+ let content = <div ref={contentRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTENT)}>
395
+ {emptyTabset}
388
396
  </div>
389
397
 
390
- var content;
391
398
  if (node.getTabLocation() === "top") {
392
- content = <>{header}{tabStrip}{center}</>;
399
+ content = <>{tabStrip}{content}</>;
393
400
  } else {
394
- content = <>{header}{center}{tabStrip}</>;
401
+ content = <>{content}{tabStrip}</>;
402
+ }
403
+
404
+ let style: Record<string, any> = {
405
+ flexGrow: Math.max(1, node.getWeight() * 1000),
406
+ minWidth: node.getMinWidth(),
407
+ minHeight: node.getMinHeight(),
408
+ maxWidth: node.getMaxWidth(),
409
+ maxHeight: node.getMaxHeight()
410
+ };
411
+
412
+ if (node.getModel().getMaximizedTabset(layout.getWindowId()) !== undefined && !node.isMaximized()) {
413
+ style.display = "none";
395
414
  }
396
415
 
397
- return (
416
+ // note: tabset container is needed to allow flexbox to size without border/padding/margin
417
+ // then inner tabset can have border/padding/margin for styling
418
+ const tabset = (
398
419
  <div ref={selfRef}
399
- dir="ltr"
400
- data-layout-path={path}
420
+ className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTAINER)}
401
421
  style={style}
402
- className={cm(CLASSES.FLEXLAYOUT__TABSET)}
403
- onWheel={onMouseWheel}>
404
- {content}
422
+ >
423
+ <div className={cm(CLASSES.FLEXLAYOUT__TABSET)}
424
+ data-layout-path={path}
425
+ >
426
+ {content}
427
+ </div>
405
428
  </div>
406
429
  );
430
+
431
+ if (node.isMaximized()) {
432
+ if (layout.getMainElement()) {
433
+ return createPortal(
434
+ <div style={{
435
+ position: "absolute",
436
+ display: "flex",
437
+ top: 0, left: 0, bottom: 0, right: 0
438
+ }}>
439
+ {tabset}
440
+ </div>, layout.getMainElement()!);
441
+ } else {
442
+ return tabset;
443
+ }
444
+ } else {
445
+ return tabset;
446
+ }
447
+
407
448
  };
408
449
 
409
450