flexlayout-react 0.5.16 → 0.5.20
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 +24 -0
- package/README.md +128 -97
- package/declarations/DragDrop.d.ts +1 -0
- package/declarations/Rect.d.ts +4 -0
- package/declarations/Types.d.ts +8 -1
- package/declarations/model/BorderNode.d.ts +2 -1
- package/declarations/model/IJsonModel.d.ts +8 -0
- package/declarations/model/Model.d.ts +1 -0
- package/declarations/view/Layout.d.ts +19 -6
- package/dist/flexlayout.js +19 -19
- package/dist/flexlayout_min.js +1 -1
- package/lib/DockLocation.js +25 -11
- package/lib/DockLocation.js.map +1 -1
- package/lib/DragDrop.js +19 -3
- package/lib/DragDrop.js.map +1 -1
- package/lib/PopupMenu.js +14 -9
- package/lib/PopupMenu.js.map +1 -1
- package/lib/Rect.js +3 -0
- package/lib/Rect.js.map +1 -1
- package/lib/Types.js +7 -0
- package/lib/Types.js.map +1 -1
- package/lib/model/BorderNode.js +61 -14
- package/lib/model/BorderNode.js.map +1 -1
- package/lib/model/BorderSet.js +33 -19
- package/lib/model/BorderSet.js.map +1 -1
- package/lib/model/Model.js +23 -3
- package/lib/model/Model.js.map +1 -1
- package/lib/model/RowNode.js +19 -5
- package/lib/model/RowNode.js.map +1 -1
- package/lib/model/TabNode.js +10 -0
- package/lib/model/TabNode.js.map +1 -1
- package/lib/model/TabSetNode.js +34 -19
- package/lib/model/TabSetNode.js.map +1 -1
- package/lib/view/BorderButton.js +17 -6
- package/lib/view/BorderButton.js.map +1 -1
- package/lib/view/BorderTabSet.js +17 -6
- package/lib/view/BorderTabSet.js.map +1 -1
- package/lib/view/Layout.js +232 -57
- package/lib/view/Layout.js.map +1 -1
- package/lib/view/Splitter.js +35 -4
- package/lib/view/Splitter.js.map +1 -1
- package/lib/view/Tab.js +2 -2
- package/lib/view/Tab.js.map +1 -1
- package/lib/view/TabButton.js +16 -7
- package/lib/view/TabButton.js.map +1 -1
- package/lib/view/TabFloating.js +24 -12
- package/lib/view/TabFloating.js.map +1 -1
- package/lib/view/TabSet.js +49 -24
- package/lib/view/TabSet.js.map +1 -1
- package/package.json +11 -6
- package/src/DockLocation.ts +30 -9
- package/src/DragDrop.ts +26 -3
- package/src/PopupMenu.tsx +32 -11
- package/src/Rect.ts +6 -2
- package/src/Types.ts +7 -0
- package/src/model/BorderNode.ts +57 -15
- package/src/model/BorderSet.ts +32 -19
- package/src/model/IJsonModel.ts +8 -0
- package/src/model/Model.ts +30 -3
- package/src/model/RowNode.ts +8 -5
- package/src/model/TabNode.ts +11 -0
- package/src/model/TabSetNode.ts +33 -19
- package/src/view/BorderButton.tsx +34 -6
- package/src/view/BorderTabSet.tsx +25 -5
- package/src/view/Layout.tsx +299 -82
- package/src/view/Splitter.tsx +53 -4
- package/src/view/Tab.tsx +8 -2
- package/src/view/TabButton.tsx +31 -7
- package/src/view/TabFloating.tsx +42 -20
- package/src/view/TabSet.tsx +70 -18
- package/style/_base.scss +78 -51
- package/style/dark.css +94 -68
- package/style/dark.css.map +1 -1
- package/style/dark.scss +20 -20
- package/style/gray.css +94 -68
- package/style/gray.css.map +1 -1
- package/style/gray.scss +20 -20
- package/style/light.css +94 -68
- package/style/light.css.map +1 -1
- package/style/light.scss +18 -18
- package/yarn-error.log +0 -11828
package/src/view/Layout.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import * as ReactDOM from "react-dom";
|
|
2
3
|
import DockLocation from "../DockLocation";
|
|
3
4
|
import DragDrop from "../DragDrop";
|
|
4
5
|
import DropInfo from "../DropInfo";
|
|
@@ -24,6 +25,12 @@ import { FloatingWindow } from "./FloatingWindow";
|
|
|
24
25
|
import { FloatingWindowTab } from "./FloatingWindowTab";
|
|
25
26
|
import { TabFloating } from "./TabFloating";
|
|
26
27
|
import { IJsonTabNode } from "../model/IJsonModel";
|
|
28
|
+
import { Orientation } from "..";
|
|
29
|
+
|
|
30
|
+
export type CustomDragCallback = (dragging: TabNode | IJsonTabNode, over: TabNode, x: number, y: number, location: DockLocation) => void;
|
|
31
|
+
export type DragRectRenderCallback = (text: String, node?: Node, json?: IJsonTabNode) => React.ReactElement | undefined;
|
|
32
|
+
export type FloatingTabPlaceholderRenderCallback = (dockPopout: () => void, showPopout: () => void) => React.ReactElement | undefined;
|
|
33
|
+
export type NodeMouseEvent = (node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
|
27
34
|
|
|
28
35
|
export interface ILayoutProps {
|
|
29
36
|
model: Model;
|
|
@@ -37,30 +44,37 @@ export interface ILayoutProps {
|
|
|
37
44
|
onAction?: (action: Action) => Action | undefined;
|
|
38
45
|
onRenderTab?: (
|
|
39
46
|
node: TabNode,
|
|
40
|
-
renderValues: ITabRenderValues,
|
|
47
|
+
renderValues: ITabRenderValues, // change the values in this object as required
|
|
41
48
|
) => void;
|
|
42
49
|
onRenderTabSet?: (
|
|
43
50
|
tabSetNode: TabSetNode | BorderNode,
|
|
44
|
-
renderValues: ITabSetRenderValues,
|
|
51
|
+
renderValues: ITabSetRenderValues, // change the values in this object as required
|
|
45
52
|
) => void;
|
|
46
53
|
onModelChange?: (model: Model) => void;
|
|
47
54
|
onExternalDrag?: (event: React.DragEvent<HTMLDivElement>) => undefined | {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
dragText: string,
|
|
56
|
+
json: any,
|
|
57
|
+
onDrop?: (node?: Node, event?: Event) => void
|
|
51
58
|
};
|
|
52
59
|
classNameMapper?: (defaultClassName: string) => string;
|
|
53
60
|
i18nMapper?: (id: I18nLabel, param?: string) => string | undefined;
|
|
54
61
|
supportsPopout?: boolean | undefined;
|
|
55
62
|
popoutURL?: string | undefined;
|
|
56
63
|
realtimeResize?: boolean | undefined;
|
|
57
|
-
onTabDrag?: (dragging: TabNode | IJsonTabNode, over: TabNode, x: number, y: number, location: DockLocation) => undefined | {
|
|
64
|
+
onTabDrag?: (dragging: TabNode | IJsonTabNode, over: TabNode, x: number, y: number, location: DockLocation, refresh: () => void) => undefined | {
|
|
58
65
|
x: number,
|
|
59
66
|
y: number,
|
|
60
67
|
width: number,
|
|
61
68
|
height: number,
|
|
62
|
-
callback:
|
|
69
|
+
callback: CustomDragCallback,
|
|
70
|
+
// Called once when `callback` is not going to be called anymore (user canceled the drag, moved mouse and you returned a different callback, etc)
|
|
71
|
+
invalidated?: () => void,
|
|
72
|
+
cursor?: string | undefined
|
|
63
73
|
};
|
|
74
|
+
onRenderDragRect?: DragRectRenderCallback;
|
|
75
|
+
onRenderFloatingTabPlaceholder?: FloatingTabPlaceholderRenderCallback;
|
|
76
|
+
onContextMenu?: NodeMouseEvent;
|
|
77
|
+
onAuxMouseClick?: NodeMouseEvent;
|
|
64
78
|
}
|
|
65
79
|
export interface IFontValues {
|
|
66
80
|
size?: string;
|
|
@@ -94,6 +108,7 @@ export interface ILayoutState {
|
|
|
94
108
|
calculatedTabBarSize: number;
|
|
95
109
|
calculatedBorderBarSize: number;
|
|
96
110
|
editingTab?: TabNode;
|
|
111
|
+
showHiddenBorder: DockLocation;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
export interface IIcons {
|
|
@@ -107,12 +122,14 @@ export interface IIcons {
|
|
|
107
122
|
|
|
108
123
|
export interface ICustomDropDestination {
|
|
109
124
|
rect: Rect;
|
|
110
|
-
callback:
|
|
125
|
+
callback: CustomDragCallback;
|
|
126
|
+
invalidated: (() => void) | undefined;
|
|
111
127
|
dragging: TabNode | IJsonTabNode;
|
|
112
128
|
over: TabNode;
|
|
113
129
|
x: number;
|
|
114
130
|
y: number;
|
|
115
131
|
location: DockLocation;
|
|
132
|
+
cursor: string | undefined;
|
|
116
133
|
}
|
|
117
134
|
|
|
118
135
|
/** @hidden @internal */
|
|
@@ -146,7 +163,9 @@ export interface ILayoutCallbacks {
|
|
|
146
163
|
styleFont: (style: Record<string, string>) => Record<string, string>;
|
|
147
164
|
setEditingTab(tabNode?: TabNode): void;
|
|
148
165
|
getEditingTab(): TabNode | undefined;
|
|
149
|
-
|
|
166
|
+
getOnRenderFloatingTabPlaceholder(): FloatingTabPlaceholderRenderCallback | undefined;
|
|
167
|
+
showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>): void;
|
|
168
|
+
auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>): void;
|
|
150
169
|
}
|
|
151
170
|
|
|
152
171
|
// Popout windows work in latest browsers based on webkit (Chrome, Opera, Safari, latest Edge) and Firefox. They do
|
|
@@ -164,6 +183,7 @@ const defaultSupportsPopout: boolean = isDesktop && !isIEorEdge;
|
|
|
164
183
|
* A React component that hosts a multi-tabbed layout
|
|
165
184
|
*/
|
|
166
185
|
export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
186
|
+
|
|
167
187
|
/** @hidden @internal */
|
|
168
188
|
private selfRef: React.RefObject<HTMLDivElement>;
|
|
169
189
|
/** @hidden @internal */
|
|
@@ -193,6 +213,8 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
193
213
|
/** @hidden @internal */
|
|
194
214
|
private dragDiv?: HTMLDivElement;
|
|
195
215
|
/** @hidden @internal */
|
|
216
|
+
private dragRectRendered: boolean = true;
|
|
217
|
+
/** @hidden @internal */
|
|
196
218
|
private dragDivText: string = "";
|
|
197
219
|
/** @hidden @internal */
|
|
198
220
|
private dropInfo: DropInfo | undefined;
|
|
@@ -230,7 +252,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
230
252
|
/** @hidden @internal */
|
|
231
253
|
private firstRender: boolean;
|
|
232
254
|
/** @hidden @internal */
|
|
233
|
-
private resizeObserver
|
|
255
|
+
private resizeObserver?: ResizeObserver;
|
|
234
256
|
|
|
235
257
|
constructor(props: ILayoutProps) {
|
|
236
258
|
super(props);
|
|
@@ -246,11 +268,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
246
268
|
this.icons = props.closeIcon ? Object.assign({ close: props.closeIcon }, props.icons) : props.icons;
|
|
247
269
|
this.firstRender = true;
|
|
248
270
|
|
|
249
|
-
this.state = {
|
|
250
|
-
|
|
251
|
-
|
|
271
|
+
this.state = {
|
|
272
|
+
rect: new Rect(0, 0, 0, 0),
|
|
273
|
+
calculatedHeaderBarSize: 25,
|
|
274
|
+
calculatedTabBarSize: 26,
|
|
252
275
|
calculatedBorderBarSize: 30,
|
|
253
276
|
editingTab: undefined,
|
|
277
|
+
showHiddenBorder: DockLocation.CENTER,
|
|
254
278
|
};
|
|
255
279
|
|
|
256
280
|
this.onDragEnter = this.onDragEnter.bind(this);
|
|
@@ -388,8 +412,8 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
388
412
|
}
|
|
389
413
|
|
|
390
414
|
/** @hidden @internal */
|
|
391
|
-
onTabDrag(
|
|
392
|
-
return this.props.onTabDrag?.(
|
|
415
|
+
onTabDrag(...args: Parameters<Required<ILayoutProps>['onTabDrag']>) {
|
|
416
|
+
return this.props.onTabDrag?.(...args);
|
|
393
417
|
}
|
|
394
418
|
|
|
395
419
|
/** @hidden @internal */
|
|
@@ -404,7 +428,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
404
428
|
|
|
405
429
|
/** @hidden @internal */
|
|
406
430
|
setEditingTab(tabNode?: TabNode) {
|
|
407
|
-
this.setState({editingTab:tabNode});
|
|
431
|
+
this.setState({ editingTab: tabNode });
|
|
408
432
|
}
|
|
409
433
|
|
|
410
434
|
/** @hidden @internal */
|
|
@@ -437,11 +461,12 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
437
461
|
tabBarSize: this.state.calculatedTabBarSize,
|
|
438
462
|
borderBarSize: this.state.calculatedBorderBarSize,
|
|
439
463
|
};
|
|
464
|
+
this.props.model._setShowHiddenBorder(this.state.showHiddenBorder);
|
|
440
465
|
|
|
441
466
|
this.centerRect = this.props.model._layout(this.state.rect, metrics);
|
|
442
467
|
|
|
443
468
|
this.renderBorder(this.props.model.getBorderSet(), borderComponents, tabComponents, floatingWindows, splitterComponents);
|
|
444
|
-
this.renderChildren(this.props.model.getRoot(), tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
469
|
+
this.renderChildren("", this.props.model.getRoot(), tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
445
470
|
|
|
446
471
|
if (this.edgesShown) {
|
|
447
472
|
this.repositionEdges(this.state.rect)
|
|
@@ -519,10 +544,12 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
519
544
|
/** @hidden @internal */
|
|
520
545
|
renderBorder(borderSet: BorderSet, borderComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
521
546
|
for (const border of borderSet.getBorders()) {
|
|
547
|
+
const borderPath = `/border/${border.getLocation().getName()}`;
|
|
522
548
|
if (border.isShowing()) {
|
|
523
549
|
borderComponents.push(
|
|
524
550
|
<BorderTabSet
|
|
525
|
-
key={
|
|
551
|
+
key={`border_${border.getLocation().getName()}`}
|
|
552
|
+
path={borderPath}
|
|
526
553
|
border={border}
|
|
527
554
|
layout={this}
|
|
528
555
|
iconFactory={this.props.iconFactory}
|
|
@@ -532,10 +559,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
532
559
|
);
|
|
533
560
|
const drawChildren = border._getDrawChildren();
|
|
534
561
|
let i = 0;
|
|
562
|
+
let tabCount = 0;
|
|
535
563
|
for (const child of drawChildren) {
|
|
536
564
|
if (child instanceof SplitterNode) {
|
|
537
|
-
|
|
565
|
+
let path = borderPath + "/s";
|
|
566
|
+
splitterComponents.push(<Splitter key={child.getId()} layout={this} node={child} path={path} />);
|
|
538
567
|
} else if (child instanceof TabNode) {
|
|
568
|
+
let path = borderPath + "/t" + tabCount++;
|
|
539
569
|
if (this.supportsPopout && child.isFloating()) {
|
|
540
570
|
const rect = this._getScreenRect(child);
|
|
541
571
|
floatingWindows.push(
|
|
@@ -551,9 +581,19 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
551
581
|
<FloatingWindowTab layout={this} node={child} factory={this.props.factory} />
|
|
552
582
|
</FloatingWindow>
|
|
553
583
|
);
|
|
554
|
-
tabComponents[child.getId()] = <TabFloating key={child.getId()}
|
|
584
|
+
tabComponents[child.getId()] = <TabFloating key={child.getId()}
|
|
585
|
+
layout={this}
|
|
586
|
+
path={path}
|
|
587
|
+
node={child}
|
|
588
|
+
selected={i === border.getSelected()
|
|
589
|
+
} />;
|
|
555
590
|
} else {
|
|
556
|
-
tabComponents[child.getId()] = <Tab key={child.getId()}
|
|
591
|
+
tabComponents[child.getId()] = <Tab key={child.getId()}
|
|
592
|
+
layout={this}
|
|
593
|
+
path={path}
|
|
594
|
+
node={child}
|
|
595
|
+
selected={i === border.getSelected()}
|
|
596
|
+
factory={this.props.factory} />;
|
|
557
597
|
}
|
|
558
598
|
}
|
|
559
599
|
i++;
|
|
@@ -563,16 +603,22 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
563
603
|
}
|
|
564
604
|
|
|
565
605
|
/** @hidden @internal */
|
|
566
|
-
renderChildren(node: RowNode | TabSetNode, tabSetComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
606
|
+
renderChildren(path: string, node: RowNode | TabSetNode, tabSetComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
567
607
|
const drawChildren = node._getDrawChildren();
|
|
608
|
+
let splitterCount = 0;
|
|
609
|
+
let tabCount = 0;
|
|
610
|
+
let rowCount = 0;
|
|
568
611
|
|
|
569
612
|
for (const child of drawChildren!) {
|
|
570
613
|
if (child instanceof SplitterNode) {
|
|
571
|
-
|
|
614
|
+
const newPath = path + "/s" + (splitterCount++);
|
|
615
|
+
splitterComponents.push(<Splitter key={child.getId()} layout={this} path={newPath} node={child} />);
|
|
572
616
|
} else if (child instanceof TabSetNode) {
|
|
573
|
-
|
|
574
|
-
|
|
617
|
+
const newPath = path + "/ts" + (rowCount++);
|
|
618
|
+
tabSetComponents.push(<TabSet key={child.getId()} layout={this} path={newPath} node={child} iconFactory={this.props.iconFactory} titleFactory={this.props.titleFactory} icons={this.icons} />);
|
|
619
|
+
this.renderChildren(newPath, child, tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
575
620
|
} else if (child instanceof TabNode) {
|
|
621
|
+
const newPath = path + "/t" + (tabCount++);
|
|
576
622
|
const selectedTab = child.getParent()!.getChildren()[(child.getParent() as TabSetNode).getSelected()];
|
|
577
623
|
if (selectedTab === undefined) {
|
|
578
624
|
// this should not happen!
|
|
@@ -593,13 +639,14 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
593
639
|
<FloatingWindowTab layout={this} node={child} factory={this.props.factory} />
|
|
594
640
|
</FloatingWindow>
|
|
595
641
|
);
|
|
596
|
-
tabComponents[child.getId()] = <TabFloating key={child.getId()} layout={this} node={child} selected={child === selectedTab} />;
|
|
642
|
+
tabComponents[child.getId()] = <TabFloating key={child.getId()} layout={this} path={newPath} node={child} selected={child === selectedTab} />;
|
|
597
643
|
} else {
|
|
598
|
-
tabComponents[child.getId()] = <Tab key={child.getId()} layout={this} node={child} selected={child === selectedTab} factory={this.props.factory} />;
|
|
644
|
+
tabComponents[child.getId()] = <Tab key={child.getId()} layout={this} path={newPath} node={child} selected={child === selectedTab} factory={this.props.factory} />;
|
|
599
645
|
}
|
|
600
646
|
} else {
|
|
601
647
|
// is row
|
|
602
|
-
|
|
648
|
+
const newPath = path + ((child.getOrientation() === Orientation.HORZ) ? "/r" : "/c") + (rowCount++);
|
|
649
|
+
this.renderChildren(newPath, child as RowNode, tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
603
650
|
}
|
|
604
651
|
}
|
|
605
652
|
}
|
|
@@ -642,7 +689,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
642
689
|
* Adds a new tab by dragging a labeled panel to the drop location, dragging starts immediatelly
|
|
643
690
|
* @param dragText the text to show on the drag panel
|
|
644
691
|
* @param json the json for the new tab node
|
|
645
|
-
* @param onDrop a callback to call when the drag is complete
|
|
692
|
+
* @param onDrop a callback to call when the drag is complete (node and event will be undefined if the drag was cancelled)
|
|
646
693
|
*/
|
|
647
694
|
addTabWithDragAndDrop(dragText: string, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
648
695
|
this.fnNewNodeDropped = onDrop;
|
|
@@ -656,9 +703,9 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
656
703
|
*
|
|
657
704
|
* @param dragText the text to show on the drag panel
|
|
658
705
|
* @param json the json for the new tab node
|
|
659
|
-
* @param onDrop a callback to call when the drag is complete
|
|
706
|
+
* @param onDrop a callback to call when the drag is complete (node and event will be undefined if the drag was cancelled)
|
|
660
707
|
*/
|
|
661
|
-
addTabWithDragAndDropIndirect(dragText: string, json: IJsonTabNode, onDrop?: () => void) {
|
|
708
|
+
addTabWithDragAndDropIndirect(dragText: string, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
662
709
|
this.fnNewNodeDropped = onDrop;
|
|
663
710
|
this.newTabJson = json;
|
|
664
711
|
|
|
@@ -666,15 +713,22 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
666
713
|
|
|
667
714
|
this.dragDivText = dragText;
|
|
668
715
|
this.dragDiv = this.currentDocument!.createElement("div");
|
|
669
|
-
this.dragDiv.className = this.getClassName(
|
|
670
|
-
this.dragDiv.innerHTML = this.dragDivText;
|
|
716
|
+
this.dragDiv.className = this.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT);
|
|
671
717
|
this.dragDiv.addEventListener("mousedown", this.onDragDivMouseDown);
|
|
672
718
|
this.dragDiv.addEventListener("touchstart", this.onDragDivMouseDown);
|
|
673
719
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
720
|
+
this.dragRectRender(this.dragDivText, undefined, this.newTabJson, () => {
|
|
721
|
+
if (this.dragDiv) {
|
|
722
|
+
// now it's been rendered into the dom it can be centered
|
|
723
|
+
this.dragDiv.style.visibility = "visible";
|
|
724
|
+
const domRect = this.dragDiv.getBoundingClientRect();
|
|
725
|
+
const r = new Rect(0, 0, domRect?.width, domRect?.height);
|
|
726
|
+
r.centerInRect(this.state.rect);
|
|
727
|
+
this.dragDiv.setAttribute("data-layout-path", "/drag-rectangle");
|
|
728
|
+
this.dragDiv.style.left = r.x + "px";
|
|
729
|
+
this.dragDiv.style.top = r.y + "px";
|
|
730
|
+
}
|
|
731
|
+
});
|
|
678
732
|
|
|
679
733
|
const rootdiv = this.selfRef.current;
|
|
680
734
|
rootdiv!.appendChild(this.dragDiv);
|
|
@@ -689,8 +743,16 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
689
743
|
this.fnNewNodeDropped();
|
|
690
744
|
this.fnNewNodeDropped = undefined;
|
|
691
745
|
}
|
|
746
|
+
|
|
747
|
+
try {
|
|
748
|
+
this.customDrop?.invalidated?.()
|
|
749
|
+
} catch (e) {
|
|
750
|
+
console.error(e)
|
|
751
|
+
}
|
|
752
|
+
|
|
692
753
|
DragDrop.instance.hideGlass();
|
|
693
754
|
this.newTabJson = undefined;
|
|
755
|
+
this.customDrop = undefined;
|
|
694
756
|
};
|
|
695
757
|
|
|
696
758
|
/** @hidden @internal */
|
|
@@ -700,11 +762,11 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
700
762
|
|
|
701
763
|
try {
|
|
702
764
|
rootdiv.removeChild(this.outlineDiv!);
|
|
703
|
-
} catch (e) {}
|
|
765
|
+
} catch (e) { }
|
|
704
766
|
|
|
705
767
|
try {
|
|
706
768
|
rootdiv.removeChild(this.dragDiv!);
|
|
707
|
-
} catch (e) {}
|
|
769
|
+
} catch (e) { }
|
|
708
770
|
|
|
709
771
|
this.dragDiv = undefined;
|
|
710
772
|
this.hideEdges(rootdiv);
|
|
@@ -712,9 +774,19 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
712
774
|
this.fnNewNodeDropped();
|
|
713
775
|
this.fnNewNodeDropped = undefined;
|
|
714
776
|
}
|
|
777
|
+
|
|
778
|
+
try {
|
|
779
|
+
this.customDrop?.invalidated?.()
|
|
780
|
+
} catch (e) {
|
|
781
|
+
console.error(e)
|
|
782
|
+
}
|
|
783
|
+
|
|
715
784
|
DragDrop.instance.hideGlass();
|
|
716
785
|
this.newTabJson = undefined;
|
|
786
|
+
this.customDrop = undefined;
|
|
717
787
|
}
|
|
788
|
+
this.setState({ showHiddenBorder: DockLocation.CENTER });
|
|
789
|
+
|
|
718
790
|
};
|
|
719
791
|
|
|
720
792
|
/** @hidden @internal */
|
|
@@ -741,6 +813,31 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
741
813
|
}
|
|
742
814
|
};
|
|
743
815
|
|
|
816
|
+
/** @hidden @internal */
|
|
817
|
+
dragRectRender = (text: String, node?: Node, json?: IJsonTabNode, onRendered?: () => void) => {
|
|
818
|
+
let content: React.ReactElement | undefined = <div style={{ whiteSpace: "pre" }}>{text.replace("<br>", "\n")}</div>;
|
|
819
|
+
|
|
820
|
+
if (this.props.onRenderDragRect !== undefined) {
|
|
821
|
+
const customContent = this.props.onRenderDragRect(text, node, json);
|
|
822
|
+
if (customContent !== undefined) {
|
|
823
|
+
content = customContent;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// hide div until the render is complete
|
|
828
|
+
this.dragDiv!.style.visibility = "hidden";
|
|
829
|
+
this.dragRectRendered = false;
|
|
830
|
+
ReactDOM.render(<DragRectRenderWrapper
|
|
831
|
+
// wait for it to be rendered
|
|
832
|
+
onRendered={() => {
|
|
833
|
+
this.dragRectRendered = true;
|
|
834
|
+
onRendered?.();
|
|
835
|
+
}}
|
|
836
|
+
>
|
|
837
|
+
{content}
|
|
838
|
+
</DragRectRenderWrapper>, this.dragDiv!);
|
|
839
|
+
};
|
|
840
|
+
|
|
744
841
|
/** @hidden @internal */
|
|
745
842
|
onDragStart = () => {
|
|
746
843
|
this.dropInfo = undefined;
|
|
@@ -754,7 +851,9 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
754
851
|
if (this.dragDiv == null) {
|
|
755
852
|
this.dragDiv = this.currentDocument!.createElement("div");
|
|
756
853
|
this.dragDiv.className = this.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT);
|
|
757
|
-
this.dragDiv.
|
|
854
|
+
this.dragDiv.setAttribute("data-layout-path", "/drag-rectangle");
|
|
855
|
+
this.dragRectRender(this.dragDivText, this.dragNode, this.newTabJson);
|
|
856
|
+
|
|
758
857
|
rootdiv.appendChild(this.dragDiv);
|
|
759
858
|
}
|
|
760
859
|
// add edge indicators
|
|
@@ -781,53 +880,33 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
781
880
|
y: event.clientY - clientRect.top,
|
|
782
881
|
};
|
|
783
882
|
|
|
784
|
-
this.
|
|
883
|
+
this.checkForBorderToShow(pos.x, pos.y);
|
|
884
|
+
|
|
885
|
+
// keep it between left & right
|
|
886
|
+
const dragRect = this.dragDiv!.getBoundingClientRect();
|
|
887
|
+
let newLeft = pos.x - dragRect.width / 2;
|
|
888
|
+
if (newLeft + dragRect.width > clientRect.width) {
|
|
889
|
+
newLeft = clientRect.width - dragRect.width;
|
|
890
|
+
}
|
|
891
|
+
newLeft = Math.max(0, newLeft);
|
|
892
|
+
|
|
893
|
+
this.dragDiv!.style.left = newLeft + "px";
|
|
785
894
|
this.dragDiv!.style.top = pos.y + 5 + "px";
|
|
895
|
+
if (this.dragRectRendered && this.dragDiv!.style.visibility === "hidden") {
|
|
896
|
+
// make visible once the drag rect has been rendered
|
|
897
|
+
this.dragDiv!.style.visibility = "visible";
|
|
898
|
+
}
|
|
786
899
|
|
|
787
900
|
let dropInfo = this.props.model._findDropTargetNode(this.dragNode!, pos.x, pos.y);
|
|
788
901
|
if (dropInfo) {
|
|
789
|
-
this.
|
|
790
|
-
|
|
791
|
-
const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
|
|
792
|
-
if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
|
|
793
|
-
const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
|
|
794
|
-
const tabRect = selected?.getRect()
|
|
795
|
-
|
|
796
|
-
if (selected && tabRect?.contains(pos.x, pos.y)) {
|
|
797
|
-
let customDrop: ICustomDropDestination | undefined = undefined;
|
|
798
|
-
|
|
799
|
-
try {
|
|
800
|
-
const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location);
|
|
801
|
-
|
|
802
|
-
if (dest) {
|
|
803
|
-
customDrop = {
|
|
804
|
-
rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
|
|
805
|
-
callback: dest.callback,
|
|
806
|
-
dragging: dragging,
|
|
807
|
-
over: selected,
|
|
808
|
-
x: pos.x - tabRect.x,
|
|
809
|
-
y: pos.y - tabRect.y,
|
|
810
|
-
location: dropInfo.location
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
} catch (e) {
|
|
814
|
-
console.error(e)
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
this.customDrop = customDrop;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
this.dropInfo = dropInfo;
|
|
822
|
-
this.outlineDiv!.className = this.getClassName(this.customDrop ? "flexlayout__outline_rect" : dropInfo.className);
|
|
823
|
-
|
|
824
|
-
if (this.customDrop) {
|
|
825
|
-
this.customDrop.rect.positionElement(this.outlineDiv!);
|
|
902
|
+
if (this.props.onTabDrag) {
|
|
903
|
+
this.handleCustomTabDrag(dropInfo, pos, event);
|
|
826
904
|
} else {
|
|
905
|
+
this.dropInfo = dropInfo;
|
|
906
|
+
this.outlineDiv!.className = this.getClassName(dropInfo.className);
|
|
827
907
|
dropInfo.rect.positionElement(this.outlineDiv!);
|
|
908
|
+
this.outlineDiv!.style.visibility = "visible";
|
|
828
909
|
}
|
|
829
|
-
|
|
830
|
-
this.outlineDiv!.style.visibility = "visible";
|
|
831
910
|
}
|
|
832
911
|
};
|
|
833
912
|
|
|
@@ -845,8 +924,12 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
845
924
|
this.newTabJson = undefined;
|
|
846
925
|
|
|
847
926
|
try {
|
|
848
|
-
const {callback, dragging, over, x, y, location} = this.customDrop;
|
|
927
|
+
const { callback, dragging, over, x, y, location } = this.customDrop;
|
|
849
928
|
callback(dragging, over, x, y, location);
|
|
929
|
+
if (this.fnNewNodeDropped != null) {
|
|
930
|
+
this.fnNewNodeDropped();
|
|
931
|
+
this.fnNewNodeDropped = undefined;
|
|
932
|
+
}
|
|
850
933
|
} catch (e) {
|
|
851
934
|
console.error(e)
|
|
852
935
|
}
|
|
@@ -862,8 +945,70 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
862
945
|
this.doAction(Actions.moveNode(this.dragNode.getId(), this.dropInfo.node.getId(), this.dropInfo.location, this.dropInfo.index));
|
|
863
946
|
}
|
|
864
947
|
}
|
|
948
|
+
this.setState({ showHiddenBorder: DockLocation.CENTER });
|
|
865
949
|
};
|
|
866
950
|
|
|
951
|
+
/** @hidden @internal */
|
|
952
|
+
private handleCustomTabDrag(dropInfo: DropInfo, pos: { x: number; y: number; }, event: React.MouseEvent<Element, MouseEvent>) {
|
|
953
|
+
let invalidated = this.customDrop?.invalidated;
|
|
954
|
+
const currentCallback = this.customDrop?.callback;
|
|
955
|
+
this.customDrop = undefined;
|
|
956
|
+
|
|
957
|
+
const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
|
|
958
|
+
if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
|
|
959
|
+
const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
|
|
960
|
+
const tabRect = selected?.getRect();
|
|
961
|
+
|
|
962
|
+
if (selected && tabRect?.contains(pos.x, pos.y)) {
|
|
963
|
+
let customDrop: ICustomDropDestination | undefined = undefined;
|
|
964
|
+
|
|
965
|
+
try {
|
|
966
|
+
const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location, () => this.onDragMove(event));
|
|
967
|
+
|
|
968
|
+
if (dest) {
|
|
969
|
+
customDrop = {
|
|
970
|
+
rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
|
|
971
|
+
callback: dest.callback,
|
|
972
|
+
invalidated: dest.invalidated,
|
|
973
|
+
dragging: dragging,
|
|
974
|
+
over: selected,
|
|
975
|
+
x: pos.x - tabRect.x,
|
|
976
|
+
y: pos.y - tabRect.y,
|
|
977
|
+
location: dropInfo.location,
|
|
978
|
+
cursor: dest.cursor
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
} catch (e) {
|
|
982
|
+
console.error(e);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
if (customDrop?.callback === currentCallback) {
|
|
986
|
+
invalidated = undefined;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
this.customDrop = customDrop;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
this.dropInfo = dropInfo;
|
|
994
|
+
this.outlineDiv!.className = this.getClassName(this.customDrop ? CLASSES.FLEXLAYOUT__OUTLINE_RECT : dropInfo.className);
|
|
995
|
+
|
|
996
|
+
if (this.customDrop) {
|
|
997
|
+
this.customDrop.rect.positionElement(this.outlineDiv!);
|
|
998
|
+
} else {
|
|
999
|
+
dropInfo.rect.positionElement(this.outlineDiv!);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
DragDrop.instance.setGlassCursorOverride(this.customDrop?.cursor);
|
|
1003
|
+
this.outlineDiv!.style.visibility = "visible";
|
|
1004
|
+
|
|
1005
|
+
try {
|
|
1006
|
+
invalidated?.();
|
|
1007
|
+
} catch (e) {
|
|
1008
|
+
console.error(e);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
867
1012
|
/** @hidden @internal */
|
|
868
1013
|
onDragEnter(event: React.DragEvent<HTMLDivElement>) {
|
|
869
1014
|
// DragDrop keeps track of number of dragenters minus the number of
|
|
@@ -879,6 +1024,40 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
879
1024
|
}
|
|
880
1025
|
}
|
|
881
1026
|
|
|
1027
|
+
|
|
1028
|
+
/** @hidden @internal */
|
|
1029
|
+
checkForBorderToShow(x: number, y: number) {
|
|
1030
|
+
const r = this.props.model._getOuterInnerRects().outer;
|
|
1031
|
+
const c = r.getCenter();
|
|
1032
|
+
const margin = this.edgeRectWidth;
|
|
1033
|
+
const offset = this.edgeRectLength / 2;
|
|
1034
|
+
|
|
1035
|
+
let overEdge = false;
|
|
1036
|
+
if (this.props.model.isEnableEdgeDock() && this.state.showHiddenBorder === DockLocation.CENTER) {
|
|
1037
|
+
if ((y > c.y - offset && y < c.y + offset) ||
|
|
1038
|
+
(x > c.x - offset && x < c.x + offset)) {
|
|
1039
|
+
overEdge = true;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
let location = DockLocation.CENTER;
|
|
1044
|
+
if (!overEdge) {
|
|
1045
|
+
if (x <= r.x + margin) {
|
|
1046
|
+
location = DockLocation.LEFT;
|
|
1047
|
+
} else if (x >= r.getRight() - margin) {
|
|
1048
|
+
location = DockLocation.RIGHT;
|
|
1049
|
+
} else if (y <= r.y + margin) {
|
|
1050
|
+
location = DockLocation.TOP;
|
|
1051
|
+
} else if (y >= r.getBottom() - margin) {
|
|
1052
|
+
location = DockLocation.BOTTOM;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (location !== this.state.showHiddenBorder) {
|
|
1057
|
+
this.setState({ showHiddenBorder: location });
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
882
1061
|
/** @hidden @internal */
|
|
883
1062
|
showEdges(rootdiv: HTMLElement) {
|
|
884
1063
|
if (this.props.model.isEnableEdgeDock()) {
|
|
@@ -952,7 +1131,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
952
1131
|
rootdiv.removeChild(this.edgeLeftDiv!);
|
|
953
1132
|
rootdiv.removeChild(this.edgeBottomDiv!);
|
|
954
1133
|
rootdiv.removeChild(this.edgeRightDiv!);
|
|
955
|
-
} catch (e) {}
|
|
1134
|
+
} catch (e) { }
|
|
956
1135
|
}
|
|
957
1136
|
|
|
958
1137
|
this.edgesShown = false;
|
|
@@ -994,6 +1173,44 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
994
1173
|
}
|
|
995
1174
|
return message;
|
|
996
1175
|
}
|
|
1176
|
+
|
|
1177
|
+
/** @hidden @internal */
|
|
1178
|
+
getOnRenderFloatingTabPlaceholder() {
|
|
1179
|
+
return this.props.onRenderFloatingTabPlaceholder;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/** @hidden @internal */
|
|
1183
|
+
showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
|
|
1184
|
+
if (this.props.onContextMenu) {
|
|
1185
|
+
this.props.onContextMenu(node, event);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/** @hidden @internal */
|
|
1190
|
+
auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
|
|
1191
|
+
if (this.props.onAuxMouseClick) {
|
|
1192
|
+
this.props.onAuxMouseClick(node, event);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
997
1195
|
}
|
|
998
1196
|
|
|
1197
|
+
// wrapper round the drag rect renderer that can call
|
|
1198
|
+
// a method once the rendering is written to the dom
|
|
1199
|
+
|
|
1200
|
+
/** @hidden @internal */
|
|
1201
|
+
interface IDragRectRenderWrapper {
|
|
1202
|
+
onRendered?: () => void;
|
|
1203
|
+
children: React.ReactNode;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/** @hidden @internal */
|
|
1207
|
+
const DragRectRenderWrapper = (props: IDragRectRenderWrapper) => {
|
|
1208
|
+
React.useEffect(() => {
|
|
1209
|
+
props.onRendered?.();
|
|
1210
|
+
}, [props]);
|
|
1211
|
+
|
|
1212
|
+
return (<React.Fragment>
|
|
1213
|
+
{props.children}
|
|
1214
|
+
</React.Fragment>)
|
|
1215
|
+
}
|
|
999
1216
|
export default Layout;
|