flexlayout-react 0.7.15 → 0.8.1

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 +28 -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 +140 -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 +459 -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 +129 -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 +919 -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 +127 -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 +272 -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 +303 -242
  200. package/src/model/Utils.ts +6 -32
  201. package/src/view/BorderButton.tsx +36 -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 +1053 -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 +39 -54
  215. package/src/view/TabButtonStamp.tsx +5 -9
  216. package/src/view/TabOverflowHook.tsx +14 -9
  217. package/src/view/TabSet.tsx +221 -176
  218. package/src/view/Utils.tsx +119 -39
  219. package/style/_base.scss +140 -34
  220. package/style/dark.css +140 -35
  221. package/style/dark.css.map +1 -1
  222. package/style/dark.scss +3 -1
  223. package/style/gray.css +139 -34
  224. package/style/gray.css.map +1 -1
  225. package/style/gray.scss +2 -0
  226. package/style/light.css +141 -36
  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 +139 -34
  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,20 @@ 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
+ if (node.isEnableDrag()) {
77
+ event.stopPropagation();
78
+ layout.setDragNode(event.nativeEvent, node as TabSetNode);
79
+ } else {
80
+ event.preventDefault();
81
+ }
82
+ } else {
83
+ event.preventDefault();
84
+ }
85
+ };
86
+
87
+ const onPointerDown = (event: React.PointerEvent<HTMLElement>) => {
60
88
  if (!isAuxMouseEvent(event)) {
61
89
  let name = node.getName();
62
90
  if (name === undefined) {
@@ -64,29 +92,21 @@ export const TabSet = (props: ITabSetProps) => {
64
92
  } else {
65
93
  name = ": " + name;
66
94
  }
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
- }
95
+ layout.doAction(Actions.setActiveTabset(node.getId(), layout.getWindowId()));
76
96
  }
77
97
  };
78
98
 
79
- const onAuxMouseClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
99
+ const onAuxMouseClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
80
100
  if (isAuxMouseEvent(event)) {
81
101
  layout.auxMouseClick(node, event);
82
102
  }
83
103
  };
84
104
 
85
- const onContextMenu = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
105
+ const onContextMenu = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
86
106
  layout.showContextMenu(node, event);
87
107
  };
88
108
 
89
- const onInterceptMouseDown = (event: React.MouseEvent | React.TouchEvent) => {
109
+ const onInterceptPointerDown = (event: React.PointerEvent) => {
90
110
  event.stopPropagation();
91
111
  };
92
112
 
@@ -107,33 +127,31 @@ export const TabSet = (props: ITabSetProps) => {
107
127
  event.stopPropagation();
108
128
  };
109
129
 
110
- const onFloatTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
130
+ const onPopoutTab = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
111
131
  if (selectedTabNode !== undefined) {
112
- layout.doAction(Actions.floatTab(selectedTabNode.getId()));
132
+ layout.doAction(Actions.popoutTab(selectedTabNode.getId()));
133
+ // layout.doAction(Actions.popoutTabset(node.getId()));
113
134
  }
114
135
  event.stopPropagation();
115
136
  };
116
137
 
117
- const onDoubleClick = (event: Event) => {
138
+ const onDoubleClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
118
139
  if (node.canMaximize()) {
119
140
  layout.maximize(node);
120
141
  }
121
142
  };
122
143
 
123
144
  // Start Render
145
+
124
146
  const cm = layout.getClassName;
125
147
 
126
148
  // 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;
149
+ if (tabStripInnerRef.current !== null && tabStripInnerRef.current!.scrollLeft !== 0) {
150
+ tabStripInnerRef.current.scrollLeft = 0;
129
151
  }
130
152
 
131
153
  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
- }
154
+ const path = node.getPath();
137
155
 
138
156
  const tabs = [];
139
157
  if (node.isEnableTabStrip()) {
@@ -147,30 +165,23 @@ export const TabSet = (props: ITabSetProps) => {
147
165
  path={path + "/tb" + i}
148
166
  key={child.getId()}
149
167
  selected={isSelected}
150
- iconFactory={iconFactory}
151
- titleFactory={titleFactory}
152
- icons={icons}
153
168
  />);
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
- }
169
+ if (i < node.getChildren().length - 1) {
170
+ tabs.push(
171
+ <div key={"divider" + i} className={cm(CLASSES.FLEXLAYOUT__TABSET_TAB_DIVIDER)}></div>
172
+ );
173
+ }
159
174
  }
160
175
  }
161
176
 
162
- const showHeader = node.getName() !== undefined;
163
177
  let stickyButtons: React.ReactNode[] = [];
164
178
  let buttons: React.ReactNode[] = [];
165
- let headerButtons: React.ReactNode[] = [];
166
179
 
167
180
  // allow customization of header contents and buttons
168
- const renderState : ITabSetRenderValues = { headerContent: node.getName(), stickyButtons, buttons, headerButtons, overflowPosition: undefined };
181
+ const renderState: ITabSetRenderValues = { stickyButtons, buttons, overflowPosition: undefined };
169
182
  layout.customizeTabSet(node, renderState);
170
- const headerContent = renderState.headerContent;
171
183
  stickyButtons = renderState.stickyButtons;
172
184
  buttons = renderState.buttons;
173
- headerButtons = renderState.headerButtons;
174
185
 
175
186
  const isTabStretch = node.isEnableSingleTabStretch() && node.getChildren().length === 1;
176
187
  const showClose = (isTabStretch && ((node.getChildren()[0] as TabNode).isEnableClose())) || node.isEnableClose();
@@ -178,16 +189,15 @@ export const TabSet = (props: ITabSetProps) => {
178
189
  if (renderState.overflowPosition === undefined) {
179
190
  renderState.overflowPosition = stickyButtons.length;
180
191
  }
181
-
192
+
182
193
  if (stickyButtons.length > 0) {
183
- if (tabsTruncated || isTabStretch) {
194
+ if (!node.isEnableTabWrap() && (tabsTruncated || isTabStretch)) {
184
195
  buttons = [...stickyButtons, ...buttons];
185
196
  } else {
186
197
  tabs.push(<div
187
198
  ref={stickyButtonsRef}
188
199
  key="sticky_buttons_container"
189
- onMouseDown={onInterceptMouseDown}
190
- onTouchStart={onInterceptMouseDown}
200
+ onPointerDown={onInterceptPointerDown}
191
201
  onDragStart={(e) => { e.preventDefault() }}
192
202
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER)}
193
203
  >
@@ -195,64 +205,67 @@ export const TabSet = (props: ITabSetProps) => {
195
205
  </div>);
196
206
  }
197
207
  }
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
- </>);
208
+
209
+ if (!node.isEnableTabWrap()) {
210
+ if (hiddenTabs.length > 0) {
211
+ const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip);
212
+ let overflowContent;
213
+ if (typeof icons.more === "function") {
214
+ overflowContent = icons.more(node, hiddenTabs);
215
+ } else {
216
+ overflowContent = (<>
217
+ {icons.more}
218
+ <div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length}</div>
219
+ </>);
220
+ }
221
+ buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,
222
+ <button
223
+ key="overflowbutton"
224
+ data-layout-path={path + "/button/overflow"}
225
+
226
+ ref={overflowbuttonRef}
227
+ className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW)}
228
+ title={overflowTitle}
229
+ onClick={onOverflowClick}
230
+ onPointerDown={onInterceptPointerDown}
231
+ >
232
+ {overflowContent}
233
+ </button>
234
+ );
209
235
  }
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
236
  }
226
237
 
227
- if (selectedTabNode !== undefined && layout.isSupportsPopout() && selectedTabNode.isEnableFloat() && !selectedTabNode.isFloating()) {
228
- const floatTitle = layout.i18nName(I18nLabel.Float_Tab);
238
+ if (selectedTabNode !== undefined &&
239
+ layout.isSupportsPopout() &&
240
+ selectedTabNode.isEnablePopout() &&
241
+ selectedTabNode.isEnablePopoutIcon() ) {
242
+
243
+ const popoutTitle = layout.i18nName(I18nLabel.Popout_Tab);
229
244
  buttons.push(
230
245
  <button
231
- key="float"
232
- data-layout-path={path + "/button/float"}
233
- title={floatTitle}
246
+ key="popout"
247
+ data-layout-path={path + "/button/popout"}
248
+ title={popoutTitle}
234
249
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_FLOAT)}
235
- onClick={onFloatTab}
236
- onMouseDown={onInterceptMouseDown}
237
- onTouchStart={onInterceptMouseDown}
250
+ onClick={onPopoutTab}
251
+ onPointerDown={onInterceptPointerDown}
238
252
  >
239
253
  {(typeof icons.popout === "function") ? icons.popout(selectedTabNode) : icons.popout}
240
254
  </button>
241
255
  );
242
256
  }
257
+
243
258
  if (node.canMaximize()) {
244
259
  const minTitle = layout.i18nName(I18nLabel.Restore);
245
260
  const maxTitle = layout.i18nName(I18nLabel.Maximize);
246
- const btns = showHeader ? headerButtons : buttons;
247
- btns.push(
261
+ buttons.push(
248
262
  <button
249
263
  key="max"
250
264
  data-layout-path={path + "/button/max"}
251
265
  title={node.isMaximized() ? minTitle : maxTitle}
252
266
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_ + (node.isMaximized() ? "max" : "min"))}
253
267
  onClick={onMaximizeToggle}
254
- onMouseDown={onInterceptMouseDown}
255
- onTouchStart={onInterceptMouseDown}
268
+ onPointerDown={onInterceptPointerDown}
256
269
  >
257
270
  {node.isMaximized() ?
258
271
  (typeof icons.restore === "function") ? icons.restore(node) : icons.restore :
@@ -263,34 +276,44 @@ export const TabSet = (props: ITabSetProps) => {
263
276
 
264
277
  if (!node.isMaximized() && showClose) {
265
278
  const title = isTabStretch ? layout.i18nName(I18nLabel.Close_Tab) : layout.i18nName(I18nLabel.Close_Tabset);
266
- const btns = showHeader ? headerButtons : buttons;
267
- btns.push(
279
+ buttons.push(
268
280
  <button
269
281
  key="close"
270
282
  data-layout-path={path + "/button/close"}
271
283
  title={title}
272
284
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON) + " " + cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_BUTTON_CLOSE)}
273
285
  onClick={isTabStretch ? onCloseTab : onClose}
274
- onMouseDown={onInterceptMouseDown}
275
- onTouchStart={onInterceptMouseDown}
286
+ onPointerDown={onInterceptPointerDown}
276
287
  >
277
288
  {(typeof icons.closeTabset === "function") ? icons.closeTabset(node) : icons.closeTabset}
278
289
  </button>
279
290
  );
280
291
  }
281
292
 
282
- const toolbar = (
283
- <div key="toolbar" ref={toolbarRef}
293
+ if (node.isActive() && node.isEnableActiveIcon()) {
294
+ const title = layout.i18nName(I18nLabel.Active_Tabset);
295
+ buttons.push(
296
+ <div
297
+ key="active"
298
+ data-layout-path={path + "/button/active"}
299
+ title={title}
300
+ className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_ICON) }
301
+ >
302
+ {(typeof icons.activeTabset === "function") ? icons.activeTabset(node) : icons.activeTabset}
303
+ </div>
304
+ );
305
+ }
306
+
307
+ const buttonbar = (
308
+ <div key="buttonbar" ref={buttonBarRef}
284
309
  className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR)}
285
- onMouseDown={onInterceptMouseDown}
286
- onTouchStart={onInterceptMouseDown}
310
+ onPointerDown={onInterceptPointerDown}
287
311
  onDragStart={(e) => { e.preventDefault() }}
288
312
  >
289
313
  {buttons}
290
314
  </div>
291
315
  );
292
316
 
293
- let header;
294
317
  let tabStrip;
295
318
 
296
319
  let tabStripClasses = cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_OUTER);
@@ -299,111 +322,133 @@ export const TabSet = (props: ITabSetProps) => {
299
322
  }
300
323
  tabStripClasses += " " + CLASSES.FLEXLAYOUT__TABSET_TABBAR_OUTER_ + node.getTabLocation();
301
324
 
302
- if (node.isActive() && !showHeader) {
325
+ if (node.isActive()) {
303
326
  tabStripClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_SELECTED);
304
327
  }
305
328
 
306
- if (node.isMaximized() && !showHeader) {
329
+ if (node.isMaximized()) {
307
330
  tabStripClasses += " " + cm(CLASSES.FLEXLAYOUT__TABSET_MAXIMIZED);
308
331
  }
309
332
 
310
333
  if (isTabStretch) {
311
- const tabNode = node.getChildren()[0] as TabNode;
334
+ const tabNode = node.getChildren()[0] as TabNode;
312
335
  if (tabNode.getTabSetClassName() !== undefined) {
313
336
  tabStripClasses += " " + tabNode.getTabSetClassName();
314
337
  }
315
338
  }
316
339
 
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())}
340
+ if (node.isEnableTabWrap()) {
341
+ if (node.isEnableTabStrip()) {
342
+ tabStrip = (
343
+ <div className={tabStripClasses}
344
+ style={{ flexWrap: "wrap", gap:"1px", marginTop:"2px" }}
345
+ ref={tabStripRef}
346
+ data-layout-path={path + "/tabstrip"}
347
+ onPointerDown={onPointerDown}
348
+ onDoubleClick={onDoubleClick}
349
+ onContextMenu={onContextMenu}
350
+ onClick={onAuxMouseClick}
351
+ onAuxClick={onAuxMouseClick}
352
+ draggable={true}
353
+ onDragStart={onDragStart}
368
354
  >
369
355
  {tabs}
356
+ <div style={{ flexGrow: 1 }} />
357
+ {buttonbar}
370
358
  </div>
371
- </div>
372
- {toolbar}
373
- </div>
374
- );
375
-
376
- style = layout.styleFont(style);
359
+ );
360
+ }
361
+ } else {
362
+ if (node.isEnableTabStrip()) {
363
+ tabStrip = (
364
+ <div className={tabStripClasses}
365
+ ref={tabStripRef}
366
+ data-layout-path={path + "/tabstrip"}
367
+ onPointerDown={onPointerDown}
368
+ onDoubleClick={onDoubleClick}
369
+ onContextMenu={onContextMenu}
370
+ onClick={onAuxMouseClick}
371
+ onAuxClick={onAuxMouseClick}
372
+ draggable={true}
373
+ onWheel={onMouseWheel}
374
+ onDragStart={onDragStart}
375
+ >
376
+ <div ref={tabStripInnerRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_ + node.getTabLocation())}>
377
+ <div
378
+ style={{ left: position, width: (isTabStretch ? "100%" : "10000px") }}
379
+ className={cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER) + " " + cm(CLASSES.FLEXLAYOUT__TABSET_TABBAR_INNER_TAB_CONTAINER_ + node.getTabLocation())}
380
+ >
381
+ {tabs}
382
+ </div>
383
+ </div>
384
+ {buttonbar}
385
+ </div>
386
+ );
387
+ }
388
+ }
377
389
 
378
- var placeHolder: React.ReactNode = undefined;
390
+ var emptyTabset: React.ReactNode;
379
391
  if (node.getChildren().length === 0) {
380
392
  const placeHolderCallback = layout.getTabSetPlaceHolderCallback();
381
393
  if (placeHolderCallback) {
382
- placeHolder = placeHolderCallback(node);
394
+ emptyTabset = placeHolderCallback(node);
383
395
  }
384
396
  }
385
397
 
386
- const center = <div className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTENT)}>
387
- {placeHolder}
398
+ let content = <div ref={contentRef} className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTENT)}>
399
+ {emptyTabset}
388
400
  </div>
389
401
 
390
- var content;
391
402
  if (node.getTabLocation() === "top") {
392
- content = <>{header}{tabStrip}{center}</>;
403
+ content = <>{tabStrip}{content}</>;
393
404
  } else {
394
- content = <>{header}{center}{tabStrip}</>;
405
+ content = <>{content}{tabStrip}</>;
406
+ }
407
+
408
+ let style: Record<string, any> = {
409
+ flexGrow: Math.max(1, node.getWeight() * 1000),
410
+ minWidth: node.getMinWidth(),
411
+ minHeight: node.getMinHeight(),
412
+ maxWidth: node.getMaxWidth(),
413
+ maxHeight: node.getMaxHeight()
414
+ };
415
+
416
+ if (node.getModel().getMaximizedTabset(layout.getWindowId()) !== undefined && !node.isMaximized()) {
417
+ style.display = "none";
395
418
  }
396
419
 
397
- return (
420
+ // note: tabset container is needed to allow flexbox to size without border/padding/margin
421
+ // then inner tabset can have border/padding/margin for styling
422
+ const tabset = (
398
423
  <div ref={selfRef}
399
- dir="ltr"
400
- data-layout-path={path}
424
+ className={cm(CLASSES.FLEXLAYOUT__TABSET_CONTAINER)}
401
425
  style={style}
402
- className={cm(CLASSES.FLEXLAYOUT__TABSET)}
403
- onWheel={onMouseWheel}>
404
- {content}
426
+ >
427
+ <div className={cm(CLASSES.FLEXLAYOUT__TABSET)}
428
+ data-layout-path={path}
429
+ >
430
+ {content}
431
+ </div>
405
432
  </div>
406
433
  );
434
+
435
+ if (node.isMaximized()) {
436
+ if (layout.getMainElement()) {
437
+ return createPortal(
438
+ <div style={{
439
+ position: "absolute",
440
+ display: "flex",
441
+ top: 0, left: 0, bottom: 0, right: 0
442
+ }}>
443
+ {tabset}
444
+ </div>, layout.getMainElement()!);
445
+ } else {
446
+ return tabset;
447
+ }
448
+ } else {
449
+ return tabset;
450
+ }
451
+
407
452
  };
408
453
 
409
454