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.
- package/ChangeLog.txt +28 -0
- package/README.md +157 -330
- package/Screenshot_light.png +0 -0
- package/Screenshot_rounded.png +0 -0
- package/declarations/Attribute.d.ts +1 -1
- package/declarations/AttributeDefinitions.d.ts +1 -1
- package/declarations/DockLocation.d.ts +12 -12
- package/declarations/DropInfo.d.ts +12 -12
- package/declarations/I18nLabel.d.ts +12 -14
- package/declarations/Orientation.d.ts +7 -7
- package/declarations/PopupMenu.d.ts +1 -1
- package/declarations/Rect.d.ts +41 -28
- package/declarations/Types.d.ts +95 -79
- package/declarations/examples/demo/Utils.d.ts +4 -0
- package/declarations/index.d.ts +21 -22
- package/declarations/model/Action.d.ts +5 -5
- package/declarations/model/Actions.d.ts +127 -110
- package/declarations/model/BorderNode.d.ts +30 -34
- package/declarations/model/BorderSet.d.ts +3 -4
- package/declarations/model/ICloseType.d.ts +5 -5
- package/declarations/model/IDraggable.d.ts +2 -2
- package/declarations/model/IDropTarget.d.ts +2 -2
- package/declarations/model/IJsonModel.d.ts +811 -149
- package/declarations/model/LayoutWindow.d.ts +28 -0
- package/declarations/model/Model.d.ts +91 -86
- package/declarations/model/Node.d.ts +17 -17
- package/declarations/model/RowNode.d.ts +10 -11
- package/declarations/model/TabNode.d.ts +44 -37
- package/declarations/model/TabSetNode.d.ts +44 -41
- package/declarations/model/Utils.d.ts +1 -1
- package/declarations/model/WindowLayout.d.ts +24 -0
- package/declarations/src/Attribute.d.ts +1 -0
- package/declarations/src/AttributeDefinitions.d.ts +1 -0
- package/declarations/src/DockLocation.d.ts +12 -0
- package/declarations/src/DropInfo.d.ts +12 -0
- package/declarations/src/I18nLabel.d.ts +10 -0
- package/declarations/src/Orientation.d.ts +7 -0
- package/declarations/src/PopupMenu.d.ts +1 -0
- package/declarations/src/Rect.d.ts +31 -0
- package/declarations/src/Types.d.ts +92 -0
- package/declarations/src/index.d.ts +20 -0
- package/declarations/src/model/Action.d.ts +5 -0
- package/declarations/src/model/Actions.d.ts +110 -0
- package/declarations/src/model/BorderNode.d.ts +28 -0
- package/declarations/src/model/BorderSet.d.ts +3 -0
- package/declarations/src/model/ICloseType.d.ts +5 -0
- package/declarations/src/model/IDraggable.d.ts +2 -0
- package/declarations/src/model/IDropTarget.d.ts +2 -0
- package/declarations/src/model/IJsonModel.d.ts +153 -0
- package/declarations/src/model/Model.d.ts +98 -0
- package/declarations/src/model/Node.d.ts +16 -0
- package/declarations/src/model/RowNode.d.ts +11 -0
- package/declarations/src/model/TabNode.d.ts +36 -0
- package/declarations/src/model/TabSetNode.d.ts +37 -0
- package/declarations/src/model/Utils.d.ts +1 -0
- package/declarations/src/view/BorderButton.d.ts +1 -0
- package/declarations/src/view/BorderTab.d.ts +2 -0
- package/declarations/src/view/BorderTabSet.d.ts +1 -0
- package/declarations/src/view/DragContainer.d.ts +1 -0
- package/declarations/src/view/ErrorBoundary.d.ts +1 -0
- package/declarations/src/view/FloatingWindow.d.ts +1 -0
- package/declarations/src/view/Icons.d.ts +7 -0
- package/declarations/src/view/Layout.d.ts +113 -0
- package/declarations/src/view/Overlay.d.ts +1 -0
- package/declarations/src/view/PopupMenu.d.ts +1 -0
- package/declarations/src/view/Row.d.ts +1 -0
- package/declarations/src/view/Splitter.d.ts +1 -0
- package/declarations/src/view/Tab.d.ts +1 -0
- package/declarations/src/view/TabButton.d.ts +1 -0
- package/declarations/src/view/TabButtonStamp.d.ts +1 -0
- package/declarations/src/view/TabOverflowHook.d.ts +1 -0
- package/declarations/src/view/TabSet.d.ts +1 -0
- package/declarations/src/view/Utils.d.ts +4 -0
- package/declarations/view/BorderButton.d.ts +1 -1
- package/declarations/view/BorderTab.d.ts +2 -0
- package/declarations/view/BorderTabSet.d.ts +1 -1
- package/declarations/view/DragContainer.d.ts +1 -0
- package/declarations/view/ErrorBoundary.d.ts +1 -1
- package/declarations/view/ExtendedResizeObserver.d.ts +23 -0
- package/declarations/view/FloatingWindow.d.ts +1 -1
- package/declarations/view/Icons.d.ts +8 -7
- package/declarations/view/Layout.d.ts +140 -161
- package/declarations/view/Overlay.d.ts +1 -0
- package/declarations/view/PopoutWindow.d.ts +1 -0
- package/declarations/view/PopupMenu.d.ts +1 -0
- package/declarations/view/Row.d.ts +1 -0
- package/declarations/view/SizeTracker.d.ts +10 -0
- package/declarations/view/Splitter.d.ts +1 -1
- package/declarations/view/Tab.d.ts +1 -1
- package/declarations/view/TabButton.d.ts +1 -1
- package/declarations/view/TabButtonStamp.d.ts +1 -1
- package/declarations/view/TabOverflowHook.d.ts +1 -1
- package/declarations/view/TabSet.d.ts +1 -1
- package/declarations/view/Utils.d.ts +11 -1
- package/dist/bundles/demo.js +232052 -0
- package/dist/bundles/demo.js.map +1 -0
- package/dist/flexlayout.js +122 -92
- package/dist/flexlayout_min.js +1 -1
- package/lib/Attribute.js +42 -31
- package/lib/Attribute.js.map +1 -1
- package/lib/AttributeDefinitions.js +131 -108
- package/lib/AttributeDefinitions.js.map +1 -1
- package/lib/DockLocation.js +120 -124
- package/lib/DockLocation.js.map +1 -1
- package/lib/DropInfo.js +9 -13
- package/lib/DropInfo.js.map +1 -1
- package/lib/I18nLabel.js +13 -18
- package/lib/I18nLabel.js.map +1 -1
- package/lib/Orientation.js +22 -26
- package/lib/Orientation.js.map +1 -1
- package/lib/Rect.js +104 -72
- package/lib/Rect.js.map +1 -1
- package/lib/Types.js +96 -83
- package/lib/Types.js.map +1 -1
- package/lib/index.js +21 -38
- package/lib/index.js.map +1 -1
- package/lib/model/Action.js +6 -10
- package/lib/model/Action.js.map +1 -1
- package/lib/model/Actions.js +169 -155
- package/lib/model/Actions.js.map +1 -1
- package/lib/model/BorderNode.js +385 -406
- package/lib/model/BorderNode.js.map +1 -1
- package/lib/model/BorderSet.js +66 -121
- package/lib/model/BorderSet.js.map +1 -1
- package/lib/model/ICloseType.js +6 -9
- package/lib/model/ICloseType.js.map +1 -1
- package/lib/model/IDraggable.js +1 -2
- package/lib/model/IDropTarget.js +1 -2
- package/lib/model/IJsonModel.js +1 -2
- package/lib/model/LayoutWindow.js +83 -0
- package/lib/model/LayoutWindow.js.map +1 -0
- package/lib/model/Model.js +614 -496
- package/lib/model/Model.js.map +1 -1
- package/lib/model/Node.js +217 -228
- package/lib/model/Node.js.map +1 -1
- package/lib/model/RowNode.js +491 -504
- package/lib/model/RowNode.js.map +1 -1
- package/lib/model/TabNode.js +289 -184
- package/lib/model/TabNode.js.map +1 -1
- package/lib/model/TabSetNode.js +459 -446
- package/lib/model/TabSetNode.js.map +1 -1
- package/lib/model/Utils.js +47 -82
- package/lib/model/Utils.js.map +1 -1
- package/lib/view/BorderButton.js +129 -138
- package/lib/view/BorderButton.js.map +1 -1
- package/lib/view/BorderTab.js +47 -0
- package/lib/view/BorderTab.js.map +1 -0
- package/lib/view/BorderTabSet.js +134 -128
- package/lib/view/BorderTabSet.js.map +1 -1
- package/lib/view/DragContainer.js +16 -0
- package/lib/view/DragContainer.js.map +1 -0
- package/lib/view/ErrorBoundary.js +23 -27
- package/lib/view/ErrorBoundary.js.map +1 -1
- package/lib/view/Icons.js +40 -45
- package/lib/view/Icons.js.map +1 -1
- package/lib/view/Layout.js +919 -907
- package/lib/view/Layout.js.map +1 -1
- package/lib/view/Overlay.js +9 -0
- package/lib/view/Overlay.js.map +1 -0
- package/lib/view/PopoutWindow.js +129 -0
- package/lib/view/PopoutWindow.js.map +1 -0
- package/lib/view/PopupMenu.js +71 -0
- package/lib/view/PopupMenu.js.map +1 -0
- package/lib/view/Row.js +45 -0
- package/lib/view/Row.js.map +1 -0
- package/lib/view/SizeTracker.js +11 -0
- package/lib/view/SizeTracker.js.map +1 -0
- package/lib/view/Splitter.js +191 -147
- package/lib/view/Splitter.js.map +1 -1
- package/lib/view/Tab.js +86 -60
- package/lib/view/Tab.js.map +1 -1
- package/lib/view/TabButton.js +127 -135
- package/lib/view/TabButton.js.map +1 -1
- package/lib/view/TabButtonStamp.js +16 -21
- package/lib/view/TabButtonStamp.js.map +1 -1
- package/lib/view/TabOverflowHook.js +150 -149
- package/lib/view/TabOverflowHook.js.map +1 -1
- package/lib/view/TabSet.js +272 -234
- package/lib/view/TabSet.js.map +1 -1
- package/lib/view/Utils.js +126 -68
- package/lib/view/Utils.js.map +1 -1
- package/package.json +36 -30
- package/src/Attribute.ts +23 -0
- package/src/AttributeDefinitions.ts +38 -15
- package/src/DockLocation.ts +13 -13
- package/src/I18nLabel.ts +7 -9
- package/src/Rect.ts +53 -1
- package/src/Types.ts +16 -0
- package/src/index.ts +1 -2
- package/src/model/Actions.ts +49 -29
- package/src/model/BorderNode.ts +208 -214
- package/src/model/BorderSet.ts +42 -91
- package/src/model/IJsonModel.ts +883 -103
- package/src/model/LayoutWindow.ts +121 -0
- package/src/model/Model.ts +488 -366
- package/src/model/Node.ts +98 -111
- package/src/model/RowNode.ts +323 -319
- package/src/model/TabNode.ts +294 -110
- package/src/model/TabSetNode.ts +303 -242
- package/src/model/Utils.ts +6 -32
- package/src/view/BorderButton.tsx +36 -52
- package/src/view/BorderTab.tsx +70 -0
- package/src/view/BorderTabSet.tsx +64 -52
- package/src/view/DragContainer.tsx +32 -0
- package/src/view/Icons.tsx +6 -0
- package/src/view/Layout.tsx +1053 -1046
- package/src/view/Overlay.tsx +22 -0
- package/src/view/PopoutWindow.tsx +152 -0
- package/src/{PopupMenu.tsx → view/PopupMenu.tsx} +36 -31
- package/src/view/Row.tsx +68 -0
- package/src/view/SizeTracker.tsx +20 -0
- package/src/view/Splitter.tsx +167 -112
- package/src/view/Tab.tsx +76 -42
- package/src/view/TabButton.tsx +39 -54
- package/src/view/TabButtonStamp.tsx +5 -9
- package/src/view/TabOverflowHook.tsx +14 -9
- package/src/view/TabSet.tsx +221 -176
- package/src/view/Utils.tsx +119 -39
- package/style/_base.scss +140 -34
- package/style/dark.css +140 -35
- package/style/dark.css.map +1 -1
- package/style/dark.scss +3 -1
- package/style/gray.css +139 -34
- package/style/gray.css.map +1 -1
- package/style/gray.scss +2 -0
- package/style/light.css +141 -36
- package/style/light.css.map +1 -1
- package/style/light.scss +4 -2
- package/style/rounded.css +697 -0
- package/style/rounded.css.map +1 -0
- package/style/rounded.scss +194 -0
- package/style/underline.css +139 -34
- package/style/underline.css.map +1 -1
- package/style/underline.scss +2 -0
- package/cypress.config.ts +0 -16
- package/lib/DragDrop.js +0 -316
- package/lib/DragDrop.js.map +0 -1
- package/lib/PopupMenu.js +0 -68
- package/lib/PopupMenu.js.map +0 -1
- package/lib/model/SplitterNode.js +0 -72
- package/lib/model/SplitterNode.js.map +0 -1
- package/lib/view/FloatingWindow.js +0 -123
- package/lib/view/FloatingWindow.js.map +0 -1
- package/lib/view/FloatingWindowTab.js +0 -19
- package/lib/view/FloatingWindowTab.js.map +0 -1
- package/lib/view/TabFloating.js +0 -66
- package/lib/view/TabFloating.js.map +0 -1
- package/src/DragDrop.ts +0 -392
- package/src/model/SplitterNode.ts +0 -78
- package/src/view/FloatingWindow.tsx +0 -140
- package/src/view/FloatingWindowTab.tsx +0 -29
- package/src/view/TabFloating.tsx +0 -101
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LayoutInternal } from "./Layout";
|
|
3
|
+
import { CLASSES } from "../Types";
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export interface IOverlayProps {
|
|
7
|
+
layout: LayoutInternal;
|
|
8
|
+
show: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** @internal */
|
|
12
|
+
export const Overlay = (props: IOverlayProps) => {
|
|
13
|
+
const {layout, show} = props;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
className={layout.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_OVERLAY)}
|
|
18
|
+
style={{display: (show ? "flex" : "none")
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
3
|
+
import { CLASSES } from "../Types";
|
|
4
|
+
import { LayoutInternal } from "./Layout";
|
|
5
|
+
import { LayoutWindow } from "../model/LayoutWindow";
|
|
6
|
+
|
|
7
|
+
/** @internal */
|
|
8
|
+
export interface IPopoutWindowProps {
|
|
9
|
+
title: string;
|
|
10
|
+
layout: LayoutInternal;
|
|
11
|
+
layoutWindow: LayoutWindow;
|
|
12
|
+
url: string;
|
|
13
|
+
onCloseWindow: (layoutWindow: LayoutWindow) => void;
|
|
14
|
+
onSetWindow: (layoutWindow: LayoutWindow, window: Window) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
export const PopoutWindow = (props: React.PropsWithChildren<IPopoutWindowProps>) => {
|
|
19
|
+
const { title, layout, layoutWindow, url, onCloseWindow, onSetWindow, children } = props; const popoutWindow = React.useRef<Window | null>(null);
|
|
20
|
+
const [content, setContent] = React.useState<HTMLElement | undefined>(undefined);
|
|
21
|
+
// map from main docs style -> this docs equivalent style
|
|
22
|
+
const styleMap = new Map<HTMLElement, HTMLElement>();
|
|
23
|
+
|
|
24
|
+
React.useLayoutEffect(() => {
|
|
25
|
+
if (!popoutWindow.current) { // only create window once, even in strict mode
|
|
26
|
+
const windowId = layoutWindow.windowId;
|
|
27
|
+
const rect = layoutWindow.rect;
|
|
28
|
+
|
|
29
|
+
popoutWindow.current = window.open(url, windowId, `left=${rect.x},top=${rect.y},width=${rect.width},height=${rect.height}`);
|
|
30
|
+
|
|
31
|
+
if (popoutWindow.current) {
|
|
32
|
+
layoutWindow.window = popoutWindow.current;
|
|
33
|
+
onSetWindow(layoutWindow, popoutWindow.current);
|
|
34
|
+
|
|
35
|
+
// listen for parent unloading to remove all popouts
|
|
36
|
+
window.addEventListener("beforeunload", () => {
|
|
37
|
+
if (popoutWindow.current) {
|
|
38
|
+
const closedWindow = popoutWindow.current;
|
|
39
|
+
popoutWindow.current = null; // need to set to null before close, since this will trigger popup window before unload...
|
|
40
|
+
closedWindow.close();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
popoutWindow.current.addEventListener("load", () => {
|
|
45
|
+
if (popoutWindow.current) {
|
|
46
|
+
popoutWindow.current.focus();
|
|
47
|
+
|
|
48
|
+
// note: resizeto must be before moveto in chrome otherwise the window will end up at 0,0
|
|
49
|
+
popoutWindow.current.resizeTo(rect.width, rect.height);
|
|
50
|
+
popoutWindow.current.moveTo(rect.x, rect.y);
|
|
51
|
+
|
|
52
|
+
const popoutDocument = popoutWindow.current.document;
|
|
53
|
+
popoutDocument.title = title;
|
|
54
|
+
const popoutContent = popoutDocument.createElement("div");
|
|
55
|
+
popoutContent.className = CLASSES.FLEXLAYOUT__FLOATING_WINDOW_CONTENT;
|
|
56
|
+
popoutDocument.body.appendChild(popoutContent);
|
|
57
|
+
copyStyles(popoutDocument, styleMap).then(() => {
|
|
58
|
+
setContent(popoutContent); // re-render once link styles loaded
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// listen for style mutations
|
|
62
|
+
const observer = new MutationObserver((mutationsList: any) => handleStyleMutations(mutationsList, popoutDocument, styleMap));
|
|
63
|
+
observer.observe(document.head, { childList: true });
|
|
64
|
+
|
|
65
|
+
// listen for popout unloading (needs to be after load for safari)
|
|
66
|
+
popoutWindow.current.addEventListener("beforeunload", () => {
|
|
67
|
+
if (popoutWindow.current) {
|
|
68
|
+
onCloseWindow(layoutWindow); // remove the layoutWindow in the model
|
|
69
|
+
popoutWindow.current = null;
|
|
70
|
+
observer.disconnect();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
console.warn(`Unable to open window ${url}`);
|
|
77
|
+
onCloseWindow(layoutWindow); // remove the layoutWindow in the model
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return () => {
|
|
81
|
+
// only close popoutWindow if windowId has been removed from the model (ie this was due to model change)
|
|
82
|
+
if (!layout.getModel().getwindowsMap().has(layoutWindow.windowId)) {
|
|
83
|
+
popoutWindow.current?.close();
|
|
84
|
+
popoutWindow.current = null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
89
|
+
if (content !== undefined) {
|
|
90
|
+
return createPortal(children, content!);
|
|
91
|
+
} else {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
function handleStyleMutations(mutationsList: any, popoutDocument: Document, styleMap: Map<HTMLElement, HTMLElement>) {
|
|
97
|
+
for (const mutation of mutationsList) {
|
|
98
|
+
if (mutation.type === 'childList') {
|
|
99
|
+
for (const addition of mutation.addedNodes) {
|
|
100
|
+
if (addition instanceof HTMLLinkElement || addition instanceof HTMLStyleElement) {
|
|
101
|
+
copyStyle(popoutDocument, addition, styleMap);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const removal of mutation.removedNodes) {
|
|
105
|
+
if (removal instanceof HTMLLinkElement || removal instanceof HTMLStyleElement) {
|
|
106
|
+
const popoutStyle = styleMap.get(removal);
|
|
107
|
+
if (popoutStyle) {
|
|
108
|
+
popoutDocument.head.removeChild(popoutStyle);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
/** @internal */
|
|
119
|
+
function copyStyles(popoutDoc: Document, styleMap: Map<HTMLElement, HTMLElement>): Promise<boolean[]> {
|
|
120
|
+
const promises: Promise<boolean>[] = [];
|
|
121
|
+
const styleElements = document.querySelectorAll('style, link[rel="stylesheet"]') as NodeListOf<HTMLElement>
|
|
122
|
+
for (const element of styleElements) {
|
|
123
|
+
copyStyle(popoutDoc, element, styleMap, promises);
|
|
124
|
+
}
|
|
125
|
+
return Promise.all(promises);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** @internal */
|
|
129
|
+
function copyStyle(popoutDoc: Document, element: HTMLElement, styleMap: Map<HTMLElement, HTMLElement>, promises?: Promise<boolean>[]) {
|
|
130
|
+
if (element instanceof HTMLLinkElement) {
|
|
131
|
+
// prefer links since they will keep paths to images etc
|
|
132
|
+
const linkElement = element.cloneNode(true) as HTMLLinkElement;
|
|
133
|
+
popoutDoc.head.appendChild(linkElement);
|
|
134
|
+
styleMap.set(element, linkElement);
|
|
135
|
+
|
|
136
|
+
if (promises) {
|
|
137
|
+
promises.push(new Promise((resolve) => {
|
|
138
|
+
linkElement.onload = () => resolve(true);
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
} else if (element instanceof HTMLStyleElement) {
|
|
142
|
+
try {
|
|
143
|
+
const styleElement = element.cloneNode(true) as HTMLStyleElement;
|
|
144
|
+
popoutDoc.head.appendChild(styleElement);
|
|
145
|
+
styleMap.set(element, styleElement);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
// can throw an exception
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { TabButtonStamp } from "./view/TabButtonStamp";
|
|
2
|
+
import { TabNode } from "../model/TabNode";
|
|
3
|
+
import { CLASSES } from "../Types";
|
|
4
|
+
import { LayoutInternal } from "./Layout";
|
|
5
|
+
import { TabButtonStamp } from "./TabButtonStamp";
|
|
7
6
|
|
|
8
7
|
/** @internal */
|
|
9
8
|
export function showPopup(
|
|
10
9
|
triggerElement: Element,
|
|
11
10
|
items: { index: number; node: TabNode }[],
|
|
12
11
|
onSelect: (item: { index: number; node: TabNode }) => void,
|
|
13
|
-
layout:
|
|
14
|
-
iconFactory?: IconFactory,
|
|
15
|
-
titleFactory?: TitleFactory,
|
|
12
|
+
layout: LayoutInternal,
|
|
16
13
|
) {
|
|
17
14
|
const layoutDiv = layout.getRootDiv();
|
|
18
15
|
const classNameMapper = layout.getClassName;
|
|
@@ -33,43 +30,41 @@ export function showPopup(
|
|
|
33
30
|
} else {
|
|
34
31
|
elm.style.bottom = layoutRect.bottom - triggerRect.bottom + "px";
|
|
35
32
|
}
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
|
|
34
|
+
layout.showOverlay(true);
|
|
38
35
|
|
|
39
36
|
if (layoutDiv) {
|
|
40
37
|
layoutDiv.appendChild(elm);
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
const onHide = () => {
|
|
44
|
-
layout.
|
|
45
|
-
|
|
41
|
+
layout.hideControlInPortal();
|
|
42
|
+
layout.showOverlay(false);
|
|
46
43
|
if (layoutDiv) {
|
|
47
44
|
layoutDiv.removeChild(elm);
|
|
48
45
|
}
|
|
49
|
-
elm.removeEventListener("
|
|
50
|
-
currentDocument.removeEventListener("
|
|
46
|
+
elm.removeEventListener("pointerdown", onElementPointerDown);
|
|
47
|
+
currentDocument.removeEventListener("pointerdown", onDocPointerDown);
|
|
51
48
|
};
|
|
52
49
|
|
|
53
|
-
const
|
|
50
|
+
const onElementPointerDown = (event: Event) => {
|
|
54
51
|
event.stopPropagation();
|
|
55
52
|
};
|
|
56
53
|
|
|
57
|
-
const
|
|
54
|
+
const onDocPointerDown = (_event: Event) => {
|
|
58
55
|
onHide();
|
|
59
56
|
};
|
|
60
57
|
|
|
61
|
-
elm.addEventListener("
|
|
62
|
-
currentDocument.addEventListener("
|
|
58
|
+
elm.addEventListener("pointerdown", onElementPointerDown);
|
|
59
|
+
currentDocument.addEventListener("pointerdown", onDocPointerDown);
|
|
63
60
|
|
|
64
|
-
layout.
|
|
61
|
+
layout.showControlInPortal(<PopupMenu
|
|
65
62
|
currentDocument={currentDocument}
|
|
66
63
|
onSelect={onSelect}
|
|
67
64
|
onHide={onHide}
|
|
68
65
|
items={items}
|
|
69
66
|
classNameMapper={classNameMapper}
|
|
70
67
|
layout={layout}
|
|
71
|
-
iconFactory={iconFactory}
|
|
72
|
-
titleFactory={titleFactory}
|
|
73
68
|
/>, elm);
|
|
74
69
|
}
|
|
75
70
|
|
|
@@ -80,35 +75,45 @@ interface IPopupMenuProps {
|
|
|
80
75
|
onHide: () => void;
|
|
81
76
|
onSelect: (item: { index: number; node: TabNode }) => void;
|
|
82
77
|
classNameMapper: (defaultClassName: string) => string;
|
|
83
|
-
layout:
|
|
84
|
-
iconFactory?: IconFactory;
|
|
85
|
-
titleFactory?: TitleFactory;
|
|
78
|
+
layout: LayoutInternal;
|
|
86
79
|
}
|
|
87
80
|
|
|
88
81
|
/** @internal */
|
|
89
82
|
const PopupMenu = (props: IPopupMenuProps) => {
|
|
90
|
-
const { items, onHide, onSelect, classNameMapper, layout
|
|
83
|
+
const { items, onHide, onSelect, classNameMapper, layout} = props;
|
|
91
84
|
|
|
92
|
-
const onItemClick = (item: { index: number; node: TabNode }, event: React.MouseEvent<
|
|
85
|
+
const onItemClick = (item: { index: number; node: TabNode }, event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
93
86
|
onSelect(item);
|
|
94
87
|
onHide();
|
|
95
88
|
event.stopPropagation();
|
|
96
89
|
};
|
|
97
90
|
|
|
91
|
+
const onDragStart = (event: React.DragEvent<HTMLElement>, node:TabNode) => {
|
|
92
|
+
event.stopPropagation(); // prevent starting a tabset drag as well
|
|
93
|
+
layout.setDragNode(event.nativeEvent, node as TabNode);
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
onHide();
|
|
96
|
+
}, 0);
|
|
97
|
+
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const onDragEnd = (event: React.DragEvent<HTMLElement>) => {
|
|
101
|
+
layout.clearDragMain();
|
|
102
|
+
};
|
|
103
|
+
|
|
98
104
|
const itemElements = items.map((item, i) => (
|
|
99
105
|
<div key={item.index}
|
|
100
106
|
className={classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU_ITEM)}
|
|
101
107
|
data-layout-path={"/popup-menu/tb" + i}
|
|
102
108
|
onClick={(event) => onItemClick(item, event)}
|
|
109
|
+
draggable={true}
|
|
110
|
+
onDragStart={(e) => onDragStart(e, item.node)}
|
|
111
|
+
onDragEnd={onDragEnd}
|
|
103
112
|
title={item.node.getHelpText()} >
|
|
104
|
-
{item.node.getModel().isLegacyOverflowMenu() ?
|
|
105
|
-
item.node._getNameForOverflowMenu() :
|
|
106
113
|
<TabButtonStamp
|
|
107
114
|
node={item.node}
|
|
108
115
|
layout={layout}
|
|
109
|
-
|
|
110
|
-
titleFactory={titleFactory}
|
|
111
|
-
/>}
|
|
116
|
+
/>
|
|
112
117
|
</div>
|
|
113
118
|
));
|
|
114
119
|
|
package/src/view/Row.tsx
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { RowNode } from "../model/RowNode";
|
|
3
|
+
import { TabSetNode } from "../model/TabSetNode";
|
|
4
|
+
import { CLASSES } from "../Types";
|
|
5
|
+
import { LayoutInternal } from "./Layout";
|
|
6
|
+
import { TabSet } from "./TabSet";
|
|
7
|
+
import { Splitter } from "./Splitter";
|
|
8
|
+
import { Orientation } from "../Orientation";
|
|
9
|
+
|
|
10
|
+
/** @internal */
|
|
11
|
+
export interface IRowProps {
|
|
12
|
+
layout: LayoutInternal;
|
|
13
|
+
node: RowNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** @internal */
|
|
17
|
+
export const Row = (props: IRowProps) => {
|
|
18
|
+
const { layout, node } = props;
|
|
19
|
+
const selfRef = React.useRef<HTMLDivElement | null>(null);
|
|
20
|
+
|
|
21
|
+
const horizontal = node.getOrientation() === Orientation.HORZ;
|
|
22
|
+
|
|
23
|
+
React.useLayoutEffect(() => {
|
|
24
|
+
node.setRect(layout.getBoundingClientRect(selfRef.current!));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const items: React.ReactNode[] = [];
|
|
28
|
+
|
|
29
|
+
let i = 0;
|
|
30
|
+
|
|
31
|
+
for (const child of node.getChildren()) {
|
|
32
|
+
if (i > 0) {
|
|
33
|
+
items.push(<Splitter key={"splitter" + i} layout={layout} node={node} index={i} horizontal={horizontal} />)
|
|
34
|
+
}
|
|
35
|
+
if (child instanceof RowNode) {
|
|
36
|
+
items.push(<Row key={child.getId()} layout={layout} node={child} />);
|
|
37
|
+
} else if (child instanceof TabSetNode) {
|
|
38
|
+
items.push(<TabSet key={child.getId()} layout={layout} node={child} />);
|
|
39
|
+
}
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const style: Record<string, any> = {
|
|
44
|
+
flexGrow: Math.max(1, node.getWeight()*1000), // NOTE: flex-grow cannot have values < 1 otherwise will not fill parent, need to normalize
|
|
45
|
+
minWidth: node.getMinWidth(),
|
|
46
|
+
minHeight: node.getMinHeight(),
|
|
47
|
+
maxWidth: node.getMaxWidth(),
|
|
48
|
+
maxHeight: node.getMaxHeight(),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (horizontal) {
|
|
52
|
+
style.flexDirection = "row";
|
|
53
|
+
} else {
|
|
54
|
+
style.flexDirection = "column";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
ref={selfRef}
|
|
60
|
+
className={layout.getClassName(CLASSES.FLEXLAYOUT__ROW)}
|
|
61
|
+
style={style}
|
|
62
|
+
>
|
|
63
|
+
{items}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Rect } from "../Rect";
|
|
3
|
+
|
|
4
|
+
export interface ISizeTrackerProps {
|
|
5
|
+
rect: Rect;
|
|
6
|
+
selected: boolean;
|
|
7
|
+
forceRevision: number;
|
|
8
|
+
tabsRevision: number;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
// only render if size changed or forceRevision changed or tabsRevision changed
|
|
12
|
+
export const SizeTracker = React.memo(({ children }: ISizeTrackerProps) => {
|
|
13
|
+
return <>{children}</>
|
|
14
|
+
}, (prevProps, nextProps) => {
|
|
15
|
+
return prevProps.rect.equalSize(nextProps.rect) &&
|
|
16
|
+
prevProps.selected === nextProps.selected &&
|
|
17
|
+
prevProps.forceRevision === nextProps.forceRevision &&
|
|
18
|
+
prevProps.tabsRevision === nextProps.tabsRevision
|
|
19
|
+
});
|
|
20
|
+
|