flexlayout-react 0.7.14 → 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 +26 -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 -6
  82. package/declarations/view/Layout.d.ts +139 -160
  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 -40
  155. package/lib/view/Icons.js.map +1 -1
  156. package/lib/view/Layout.js +918 -901
  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 +13 -0
  206. package/src/view/Layout.tsx +1071 -1047
  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 +143 -35
  220. package/style/dark.css +685 -577
  221. package/style/dark.css.map +1 -1
  222. package/style/dark.scss +4 -1
  223. package/style/gray.css +668 -560
  224. package/style/gray.css.map +1 -1
  225. package/style/gray.scss +4 -1
  226. package/style/light.css +669 -561
  227. package/style/light.css.map +1 -1
  228. package/style/light.scss +6 -3
  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 -582
  233. package/style/underline.css.map +1 -1
  234. package/style/underline.scss +4 -1
  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
@@ -1,133 +1,167 @@
1
1
  import * as React from "react";
2
- import { DragDrop } from "../DragDrop";
3
2
  import { Actions } from "../model/Actions";
4
3
  import { BorderNode } from "../model/BorderNode";
5
- import { Node } from "../model/Node";
6
4
  import { RowNode } from "../model/RowNode";
7
- import { SplitterNode } from "../model/SplitterNode";
8
5
  import { Orientation } from "../Orientation";
9
6
  import { CLASSES } from "../Types";
10
- import { ILayoutCallbacks } from "./Layout";
7
+ import { LayoutInternal } from "./Layout";
8
+ import { enablePointerOnIFrames, isDesktop, startDrag } from "./Utils";
9
+ import { Rect } from "../Rect";
11
10
 
12
11
  /** @internal */
13
12
  export interface ISplitterProps {
14
- layout: ILayoutCallbacks;
15
- node: SplitterNode;
16
- path: string;
13
+ layout: LayoutInternal;
14
+ node: RowNode | BorderNode;
15
+ index: number;
16
+ horizontal: boolean;
17
17
  }
18
18
 
19
19
  /** @internal */
20
20
  export const Splitter = (props: ISplitterProps) => {
21
- const { layout, node, path } = props;
21
+ const { layout, node, index, horizontal } = props;
22
22
 
23
+ const [dragging, setDragging] = React.useState<boolean>(false);
24
+ const selfRef = React.useRef<HTMLDivElement | null>(null);
25
+ const extendedRef = React.useRef<HTMLDivElement | null>(null);
23
26
  const pBounds = React.useRef<number[]>([]);
24
27
  const outlineDiv = React.useRef<HTMLDivElement | undefined>(undefined);
25
- const parentNode = node.getParent() as RowNode | BorderNode;
26
-
27
- const onMouseDown = (
28
- event:
29
- | Event
30
- | React.MouseEvent<HTMLDivElement, MouseEvent>
31
- | React.TouchEvent<HTMLDivElement>
32
- ) => {
33
- DragDrop.instance.setGlassCursorOverride(
34
- node.getOrientation() === Orientation.HORZ
35
- ? "ns-resize"
36
- : "ew-resize"
37
- );
38
- DragDrop.instance.startDrag(
39
- event,
40
- onDragStart,
41
- onDragMove,
42
- onDragEnd,
43
- onDragCancel,
44
- undefined,
45
- undefined,
46
- layout.getCurrentDocument(),
47
- layout.getRootDiv() ?? undefined
48
- );
49
- pBounds.current = parentNode._getSplitterBounds(node, true);
28
+ const handleDiv = React.useRef<HTMLDivElement | undefined>(undefined);
29
+ const dragStartX = React.useRef<number>(0);
30
+ const dragStartY = React.useRef<number>(0);
31
+ const initalSizes = React.useRef<{ initialSizes: number[], sum: number, startPosition: number }>({ initialSizes: [], sum: 0, startPosition: 0 })
32
+ // const throttleTimer = React.useRef<NodeJS.Timeout | undefined>(undefined);
33
+
34
+ const size = node.getModel().getSplitterSize();
35
+ let extra = node.getModel().getSplitterExtra();
36
+
37
+ if (!isDesktop()) {
38
+ // make hit test area on mobile at least 30px
39
+ extra = Math.max(30, extra + size) - size;
40
+ }
41
+
42
+ React.useEffect(() => {
43
+ // Android fix: must have passive touchstart handler to prevent default handling
44
+ selfRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
45
+ extendedRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
46
+ return () => {
47
+ selfRef.current?.removeEventListener("touchstart", onTouchStart);
48
+ extendedRef.current?.removeEventListener("touchstart", onTouchStart);
49
+ }
50
+ }, []);
51
+
52
+ const onTouchStart = (event: TouchEvent) => {
53
+ event.preventDefault();
54
+ event.stopImmediatePropagation();
55
+ }
56
+
57
+ const onPointerDown = (event: React.PointerEvent<HTMLElement>) => {
58
+ event.stopPropagation();
59
+ if (node instanceof RowNode) {
60
+ initalSizes.current = node.getSplitterInitials(index);
61
+ }
62
+
63
+ enablePointerOnIFrames(false, layout.getCurrentDocument()!);
64
+ startDrag(event.currentTarget.ownerDocument, event, onDragMove, onDragEnd, onDragCancel);
65
+
66
+ pBounds.current = node.getSplitterBounds(index, true);
50
67
  const rootdiv = layout.getRootDiv();
51
68
  outlineDiv.current = layout.getCurrentDocument()!.createElement("div");
52
- outlineDiv.current.style.position = "absolute";
69
+ outlineDiv.current.style.flexDirection = horizontal ? "row" : "column";
53
70
  outlineDiv.current.className = layout.getClassName(CLASSES.FLEXLAYOUT__SPLITTER_DRAG);
54
- outlineDiv.current.style.cursor = node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize";
55
- const r = node.getRect();
56
- if (node.getOrientation() === Orientation.VERT && r.width < 2) {
57
- r.width = 2;
58
- } else if (node.getOrientation() === Orientation.HORZ && r.height < 2) {
59
- r.height = 2;
71
+ outlineDiv.current.style.cursor = node.getOrientation() === Orientation.VERT ? "ns-resize" : "ew-resize";
72
+
73
+ if (node.getModel().isSplitterEnableHandle()) {
74
+ handleDiv.current = layout.getCurrentDocument()!.createElement("div");
75
+ handleDiv.current.className = cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE) + " " +
76
+ (horizontal ? cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE_HORZ) : cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE_VERT));
77
+ outlineDiv.current.appendChild(handleDiv.current);
60
78
  }
61
79
 
62
- r.positionElement(outlineDiv.current);
80
+ const r = selfRef.current?.getBoundingClientRect()!;
81
+ const rect = new Rect(
82
+ r.x - layout.getDomRect()!.x,
83
+ r.y - layout.getDomRect()!.y,
84
+ r.width,
85
+ r.height
86
+ );
87
+
88
+ dragStartX.current = event.clientX - r.x;
89
+ dragStartY.current = event.clientY - r.y;
90
+
91
+ rect.positionElement(outlineDiv.current);
63
92
  if (rootdiv) {
64
93
  rootdiv.appendChild(outlineDiv.current);
65
94
  }
95
+
96
+ setDragging(true);
66
97
  };
67
98
 
68
- const onDragCancel = (_wasDragging: boolean) => {
99
+ const onDragCancel = () => {
69
100
  const rootdiv = layout.getRootDiv();
70
- if (rootdiv) {
101
+ if (rootdiv && outlineDiv.current) {
71
102
  rootdiv.removeChild(outlineDiv.current as Element);
72
103
  }
104
+ outlineDiv.current = undefined;
105
+ setDragging(false);
73
106
  };
74
107
 
75
- const onDragStart = () => {
76
- return true;
77
- };
108
+ const onDragMove = (x: number, y: number) => {
78
109
 
79
- const onDragMove = (event: React.MouseEvent<Element, MouseEvent>) => {
80
- const clientRect = layout.getDomRect();
81
- if (!clientRect) {
82
- return;
83
- }
84
-
85
- const pos = {
86
- x: event.clientX - clientRect.left,
87
- y: event.clientY - clientRect.top,
88
- };
89
-
90
- if (outlineDiv) {
91
- if (node.getOrientation() === Orientation.HORZ) {
92
- outlineDiv.current!.style.top = getBoundPosition(pos.y - 4) + "px";
110
+ if (outlineDiv.current) {
111
+ const clientRect = layout.getDomRect();
112
+ if (!clientRect) {
113
+ return;
114
+ }
115
+ if (node.getOrientation() === Orientation.VERT) {
116
+ outlineDiv.current!.style.top = getBoundPosition(y - clientRect.y - dragStartY.current) + "px";
93
117
  } else {
94
- outlineDiv.current!.style.left = getBoundPosition(pos.x - 4) + "px";
118
+ outlineDiv.current!.style.left = getBoundPosition(x - clientRect.x - dragStartX.current) + "px";
95
119
  }
96
- }
97
120
 
98
- if (layout.isRealtimeResize()) {
99
- updateLayout();
121
+ if (layout.isRealtimeResize()) {
122
+ updateLayout(true);
123
+ }
100
124
  }
101
125
  };
102
126
 
103
- const updateLayout = () => {
104
- let value = 0;
105
- if (outlineDiv) {
106
- if (node.getOrientation() === Orientation.HORZ) {
107
- value = outlineDiv.current!.offsetTop;
108
- } else {
109
- value = outlineDiv.current!.offsetLeft;
110
- }
111
- }
127
+ const onDragEnd = () => {
128
+ if (outlineDiv.current) {
129
+ updateLayout(false);
112
130
 
113
- if (parentNode instanceof BorderNode) {
114
- const pos = (parentNode as BorderNode)._calculateSplit(node, value);
115
- layout.doAction(Actions.adjustBorderSplit((node.getParent() as Node).getId(), pos));
116
- } else {
117
- const splitSpec = parentNode._calculateSplit(node, value);
118
- if (splitSpec !== undefined) {
119
- layout.doAction(Actions.adjustSplit(splitSpec));
131
+ const rootdiv = layout.getRootDiv();
132
+ if (rootdiv && outlineDiv.current) {
133
+ rootdiv.removeChild(outlineDiv.current as HTMLElement);
120
134
  }
135
+ outlineDiv.current = undefined;
121
136
  }
137
+ enablePointerOnIFrames(true, layout.getCurrentDocument()!);
138
+ setDragging(false);
122
139
  };
123
140
 
124
- const onDragEnd = () => {
125
- updateLayout();
141
+ const updateLayout = (realtime: boolean) => {
126
142
 
127
- const rootdiv = layout.getRootDiv();
128
- if (rootdiv) {
129
- rootdiv.removeChild(outlineDiv.current as HTMLDivElement);
130
- }
143
+ const redraw = () => {
144
+ if (outlineDiv.current) {
145
+ let value = 0;
146
+ if (node.getOrientation() === Orientation.VERT) {
147
+ value = outlineDiv.current!.offsetTop;
148
+ } else {
149
+ value = outlineDiv.current!.offsetLeft;
150
+ }
151
+
152
+
153
+ if (node instanceof BorderNode) {
154
+ const pos = (node as BorderNode).calculateSplit(node, value);
155
+ layout.doAction(Actions.adjustBorderSplit(node.getId(), pos));
156
+ } else {
157
+ const init = initalSizes.current;
158
+ const weights = node.calculateSplit(index, value, init.initialSizes, init.sum, init.startPosition);
159
+ layout.doAction(Actions.adjustWeights(node.getId(), weights));
160
+ }
161
+ }
162
+ };
163
+
164
+ redraw();
131
165
  };
132
166
 
133
167
  const getBoundPosition = (p: number) => {
@@ -144,58 +178,79 @@ export const Splitter = (props: ISplitterProps) => {
144
178
  };
145
179
 
146
180
  const cm = layout.getClassName;
147
- let r = node.getRect();
148
- const style = r.styleWithPosition({
149
- cursor: node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize",
150
- });
181
+ const style: Record<string, any> = {
182
+ cursor: horizontal ? "ew-resize" : "ns-resize",
183
+ flexDirection: horizontal ? "column" : "row"
184
+ };
151
185
  let className = cm(CLASSES.FLEXLAYOUT__SPLITTER) + " " + cm(CLASSES.FLEXLAYOUT__SPLITTER_ + node.getOrientation().getName());
152
186
 
153
- if (parentNode instanceof BorderNode) {
187
+ if (node instanceof BorderNode) {
154
188
  className += " " + cm(CLASSES.FLEXLAYOUT__SPLITTER_BORDER);
155
189
  } else {
156
- if (node.getModel().getMaximizedTabset() !== undefined) {
190
+ if (node.getModel().getMaximizedTabset(layout.getWindowId()) !== undefined) {
157
191
  style.display = "none";
158
192
  }
159
193
  }
160
194
 
161
- const extra = node.getModel().getSplitterExtra();
195
+ if (horizontal) {
196
+ style.width = size + "px";
197
+ style.minWidth = size + "px";
198
+ } else {
199
+ style.height = size + "px";
200
+ style.minHeight = size + "px";
201
+ }
202
+
203
+ let handle;
204
+ if (!dragging && node.getModel().isSplitterEnableHandle()) {
205
+ handle = (
206
+ <div
207
+ className={cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE) + " " +
208
+ (horizontal ? cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE_HORZ) : cm(CLASSES.FLEXLAYOUT__SPLITTER_HANDLE_VERT))
209
+ }>
210
+ </div>
211
+ );
212
+ }
213
+
162
214
  if (extra === 0) {
163
215
  return (<div
164
- style={style}
165
- data-layout-path={path}
166
216
  className={className}
167
- onTouchStart={onMouseDown}
168
- onMouseDown={onMouseDown}>
217
+ style={style}
218
+ ref={selfRef}
219
+ data-layout-path={node.getPath() + "/s" + (index - 1)}
220
+ onPointerDown={onPointerDown}>
221
+ {handle}
169
222
  </div>);
170
223
  } else {
171
224
  // add extended transparent div for hit testing
172
- // extends forward only, so as not to interfere with scrollbars
173
- let r2 = r.clone();
174
- r2.x = 0;
175
- r2.y = 0;
176
- if (node.getOrientation() === Orientation.VERT) {
177
- r2.width += extra;
225
+
226
+ const style2: Record<string, any> = {};
227
+ if (node.getOrientation() === Orientation.HORZ) {
228
+ style2.height = "100%";
229
+ style2.width = size + extra + "px";
230
+ style2.cursor = "ew-resize";
178
231
  } else {
179
- r2.height += extra;
232
+ style2.height = size + extra + "px";
233
+ style2.width = "100%";
234
+ style2.cursor = "ns-resize";
180
235
  }
181
- const style2 = r2.styleWithPosition({
182
- cursor: node.getOrientation() === Orientation.HORZ ? "ns-resize" : "ew-resize"
183
- });
184
236
 
185
237
  const className2 = cm(CLASSES.FLEXLAYOUT__SPLITTER_EXTRA);
186
238
 
187
239
  return (
188
240
  <div
241
+ className={className}
189
242
  style={style}
190
- data-layout-path={path}
191
- className={className}>
243
+ ref={selfRef}
244
+ data-layout-path={node.getPath() + "/s" + (index - 1)}
245
+ onPointerDown={onPointerDown}
246
+ >
192
247
  <div
193
248
  style={style2}
249
+ ref={extendedRef}
194
250
  className={className2}
195
- onTouchStart={onMouseDown}
196
- onMouseDown={onMouseDown}>
251
+ onPointerDown={onPointerDown}>
197
252
  </div>
198
253
  </div>);
199
254
  }
200
-
201
255
  };
256
+
package/src/view/Tab.tsx CHANGED
@@ -1,64 +1,98 @@
1
1
  import * as React from "react";
2
- import { Fragment } from "react";
3
- import { Actions } from "../model/Actions";
4
2
  import { TabNode } from "../model/TabNode";
5
3
  import { TabSetNode } from "../model/TabSetNode";
6
4
  import { CLASSES } from "../Types";
7
- import { ILayoutCallbacks } from "./Layout";
8
- import { ErrorBoundary } from "./ErrorBoundary";
9
- import { I18nLabel } from "../I18nLabel";
5
+ import { LayoutInternal } from "./Layout";
10
6
  import { BorderNode } from "../model/BorderNode";
11
- import { hideElement } from "./Utils";
7
+ import { Actions } from "../model/Actions";
12
8
 
13
9
  /** @internal */
14
10
  export interface ITabProps {
15
- layout: ILayoutCallbacks;
16
- selected: boolean;
11
+ layout: LayoutInternal;
17
12
  node: TabNode;
18
- factory: (node: TabNode) => React.ReactNode;
13
+ selected: boolean;
19
14
  path: string;
20
15
  }
21
16
 
22
17
  /** @internal */
23
18
  export const Tab = (props: ITabProps) => {
24
- const { layout, selected, node, factory, path } = props;
25
- const [renderComponent, setRenderComponent] = React.useState<boolean>(!props.node.isEnableRenderOnDemand() || props.selected);
19
+ const { layout, selected, node, path } = props;
20
+ const selfRef = React.useRef<HTMLDivElement | null>(null);
21
+ const firstSelect = React.useRef<boolean>(true);
22
+
23
+ const parentNode = node.getParent() as TabSetNode | BorderNode;
24
+ const rect = parentNode.getContentRect()!;
26
25
 
27
26
  React.useLayoutEffect(() => {
28
- if (!renderComponent && selected) {
29
- // load on demand
30
- // console.log("load on demand: " + node.getName());
31
- setRenderComponent(true);
27
+ const element = node.getMoveableElement()!;
28
+ selfRef.current!.appendChild(element);
29
+ node.setMoveableElement(element);
30
+
31
+ const handleScroll = () => {
32
+ node.saveScrollPosition();
33
+ };
34
+
35
+ // keep scroll position
36
+ element.addEventListener('scroll', handleScroll);
37
+
38
+ // listen for clicks to change active tabset
39
+ selfRef.current!.addEventListener("pointerdown", onPointerDown);
40
+
41
+ return () => {
42
+ element.removeEventListener('scroll', handleScroll);
43
+ if (selfRef.current) {
44
+ selfRef.current.removeEventListener("pointerdown", onPointerDown);
45
+ }
46
+ node.setVisible(false);
47
+ }
48
+ }, []);
49
+
50
+ React.useEffect(() => {
51
+ if (node.isSelected()) {
52
+ if (firstSelect.current) {
53
+ node.restoreScrollPosition(); // if window docked back in
54
+ firstSelect.current = false;
55
+ }
32
56
  }
33
57
  });
34
58
 
35
- const onMouseDown = () => {
36
- const parent = node.getParent() as TabSetNode;
37
- if (parent.getType() === TabSetNode.TYPE) {
59
+ const onPointerDown = () => {
60
+ const parent = node.getParent()!; // cannot use parentNode here since will be out of date
61
+ if (parent instanceof TabSetNode) {
38
62
  if (!parent.isActive()) {
39
- layout.doAction(Actions.setActiveTabset(parent.getId()));
63
+ layout.doAction(Actions.setActiveTabset(parent.getId(), layout.getWindowId()));
40
64
  }
41
65
  }
42
66
  };
43
67
 
68
+ node.setRect(rect); // needed for resize event
44
69
  const cm = layout.getClassName;
45
- const useVisibility = node.getModel().isUseVisibility();
70
+ const style: Record<string, any> = {};
46
71
 
47
- const parentNode = node.getParent() as TabSetNode | BorderNode;
48
- const style: Record<string, any> = node._styleWithPosition();
49
- if (!selected) {
50
- hideElement(style, useVisibility);
51
- }
72
+ rect.styleWithPosition(style);
52
73
 
53
- if (parentNode instanceof TabSetNode) {
54
- if (node.getModel().getMaximizedTabset() !== undefined && !parentNode.isMaximized()) {
55
- hideElement(style, useVisibility);
74
+ let overlay = null;
75
+
76
+ if (selected) {
77
+ node.setVisible(true);
78
+ if (document.hidden && node.isEnablePopoutOverlay()) {
79
+ const overlayStyle: Record<string, any> = {};
80
+ rect.styleWithPosition(overlayStyle);
81
+ overlay = (<div style={overlayStyle} className={cm(CLASSES.FLEXLAYOUT__TAB_OVERLAY)}></div>)
56
82
  }
83
+ } else {
84
+ style.display = "none";
85
+ node.setVisible(false);
57
86
  }
58
87
 
59
- let child;
60
- if (renderComponent) {
61
- child = factory(node);
88
+ if (parentNode instanceof TabSetNode) {
89
+ if (node.getModel().getMaximizedTabset(layout.getWindowId()) !== undefined) {
90
+ if (parentNode.isMaximized()) {
91
+ style.zIndex = 10;
92
+ } else {
93
+ style.display = "none";
94
+ }
95
+ }
62
96
  }
63
97
 
64
98
  let className = cm(CLASSES.FLEXLAYOUT__TAB);
@@ -66,22 +100,22 @@ export const Tab = (props: ITabProps) => {
66
100
  className += " " + cm(CLASSES.FLEXLAYOUT__TAB_BORDER);
67
101
  className += " " + cm(CLASSES.FLEXLAYOUT__TAB_BORDER_ + parentNode.getLocation().getName());
68
102
  }
69
-
103
+
70
104
  if (node.getContentClassName() !== undefined) {
71
105
  className += " " + node.getContentClassName();
72
106
  }
73
107
 
74
108
  return (
75
- <div
76
- className={className}
77
- data-layout-path={path}
78
- onMouseDown={onMouseDown}
79
- onTouchStart={onMouseDown}
80
- style={style}>
81
- <ErrorBoundary message={props.layout.i18nName(I18nLabel.Error_rendering_component)}>
82
- <Fragment>{child}</Fragment>
83
- </ErrorBoundary>
84
- </div>
109
+ <>
110
+ {overlay}
111
+
112
+ <div
113
+ ref={selfRef}
114
+ style={style}
115
+ className={className}
116
+ data-layout-path={path}
117
+ />
118
+ </>
85
119
  );
86
120
  };
87
121