flexlayout-react 0.5.18 → 0.6.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.
- package/ChangeLog.txt +27 -0
- package/README.md +126 -108
- package/declarations/Types.d.ts +8 -1
- package/declarations/model/IJsonModel.d.ts +3 -0
- package/declarations/model/Model.d.ts +2 -0
- package/declarations/view/Icons.d.ts +6 -0
- package/declarations/view/Layout.d.ts +8 -4
- package/declarations/view/MenuTabButton.d.ts +1 -0
- package/declarations/view/TabButtonStamp.d.ts +1 -0
- package/declarations/view/Utils.d.ts +1 -0
- package/dist/flexlayout.js +53 -17
- package/dist/flexlayout_min.js +1 -1
- package/lib/PopupMenu.js +22 -12
- package/lib/PopupMenu.js.map +1 -1
- package/lib/Types.js +7 -0
- package/lib/Types.js.map +1 -1
- package/lib/model/BorderNode.js +8 -7
- package/lib/model/BorderNode.js.map +1 -1
- package/lib/model/Model.js +15 -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 +6 -1
- package/lib/model/TabNode.js.map +1 -1
- package/lib/model/TabSetNode.js +8 -4
- package/lib/model/TabSetNode.js.map +1 -1
- package/lib/view/BorderButton.js +19 -38
- package/lib/view/BorderButton.js.map +1 -1
- package/lib/view/BorderTabSet.js +19 -8
- package/lib/view/BorderTabSet.js.map +1 -1
- package/lib/view/FloatingWindow.js +13 -5
- package/lib/view/FloatingWindow.js.map +1 -1
- package/lib/view/Icons.js +36 -0
- package/lib/view/Icons.js.map +1 -0
- package/lib/view/Layout.js +148 -71
- package/lib/view/Layout.js.map +1 -1
- package/lib/view/MenuTabButton.js +22 -0
- package/lib/view/MenuTabButton.js.map +1 -0
- package/lib/view/Splitter.js +3 -3
- package/lib/view/Splitter.js.map +1 -1
- package/lib/view/Tab.js +9 -6
- package/lib/view/Tab.js.map +1 -1
- package/lib/view/TabButton.js +20 -44
- package/lib/view/TabButton.js.map +1 -1
- package/lib/view/TabButtonStamp.js +22 -0
- package/lib/view/TabButtonStamp.js.map +1 -0
- package/lib/view/TabFloating.js +29 -15
- package/lib/view/TabFloating.js.map +1 -1
- package/lib/view/TabOverflowHook.js +1 -1
- package/lib/view/TabSet.js +40 -25
- package/lib/view/TabSet.js.map +1 -1
- package/lib/view/Utils.js +61 -0
- package/lib/view/Utils.js.map +1 -0
- package/package.json +11 -6
- package/src/I18nLabel.ts +1 -1
- package/src/PopupMenu.tsx +54 -15
- package/src/Types.ts +7 -0
- package/src/model/BorderNode.ts +8 -7
- package/src/model/IJsonModel.ts +3 -0
- package/src/model/Model.ts +19 -3
- package/src/model/RowNode.ts +8 -5
- package/src/model/TabNode.ts +6 -1
- package/src/model/TabSetNode.ts +8 -4
- package/src/view/BorderButton.tsx +38 -43
- package/src/view/BorderTabSet.tsx +34 -7
- package/src/view/FloatingWindow.tsx +14 -6
- package/src/view/Icons.tsx +36 -0
- package/src/view/Layout.tsx +179 -88
- package/src/view/Splitter.tsx +4 -1
- package/src/view/Tab.tsx +17 -6
- package/src/view/TabButton.tsx +42 -55
- package/src/view/TabButtonStamp.tsx +47 -0
- package/src/view/TabFloating.tsx +47 -23
- package/src/view/TabOverflowHook.tsx +1 -1
- package/src/view/TabSet.tsx +71 -22
- package/src/view/Utils.tsx +71 -0
- package/style/_base.scss +146 -92
- package/style/dark.css +157 -129
- package/style/dark.css.map +1 -1
- package/style/dark.scss +31 -21
- package/style/gray.css +157 -129
- package/style/gray.css.map +1 -1
- package/style/gray.scss +30 -23
- package/style/light.css +157 -129
- package/style/light.css.map +1 -1
- package/style/light.scss +30 -20
- package/images/close.png +0 -0
- package/images/maximize.png +0 -0
- package/images/more.png +0 -0
- package/images/more2.png +0 -0
- package/images/popout.png +0 -0
- package/images/restore.png +0 -0
package/src/view/Layout.tsx
CHANGED
|
@@ -25,9 +25,14 @@ import { FloatingWindow } from "./FloatingWindow";
|
|
|
25
25
|
import { FloatingWindowTab } from "./FloatingWindowTab";
|
|
26
26
|
import { TabFloating } from "./TabFloating";
|
|
27
27
|
import { IJsonTabNode } from "../model/IJsonModel";
|
|
28
|
+
import { Orientation } from "..";
|
|
29
|
+
import { CloseIcon, MaximizeIcon, OverflowIcon, PopoutIcon, RestoreIcon } from "./Icons";
|
|
30
|
+
import { TabButtonStamp } from "./TabButtonStamp";
|
|
28
31
|
|
|
29
32
|
export type CustomDragCallback = (dragging: TabNode | IJsonTabNode, over: TabNode, x: number, y: number, location: DockLocation) => void;
|
|
30
|
-
export type DragRectRenderCallback = (
|
|
33
|
+
export type DragRectRenderCallback = (content: React.ReactElement | undefined, node?: Node, json?: IJsonTabNode) => React.ReactElement | undefined;
|
|
34
|
+
export type FloatingTabPlaceholderRenderCallback = (dockPopout: () => void, showPopout: () => void) => React.ReactElement | undefined;
|
|
35
|
+
export type NodeMouseEvent = (node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
|
31
36
|
|
|
32
37
|
export interface ILayoutProps {
|
|
33
38
|
model: Model;
|
|
@@ -36,16 +41,15 @@ export interface ILayoutProps {
|
|
|
36
41
|
fontFamily?: string;
|
|
37
42
|
iconFactory?: (node: TabNode) => React.ReactNode | undefined;
|
|
38
43
|
titleFactory?: (node: TabNode) => ITitleObject | React.ReactNode | undefined;
|
|
39
|
-
closeIcon?: React.ReactNode;
|
|
40
44
|
icons?: IIcons;
|
|
41
45
|
onAction?: (action: Action) => Action | undefined;
|
|
42
46
|
onRenderTab?: (
|
|
43
47
|
node: TabNode,
|
|
44
|
-
renderValues: ITabRenderValues,
|
|
48
|
+
renderValues: ITabRenderValues, // change the values in this object as required
|
|
45
49
|
) => void;
|
|
46
50
|
onRenderTabSet?: (
|
|
47
51
|
tabSetNode: TabSetNode | BorderNode,
|
|
48
|
-
renderValues: ITabSetRenderValues,
|
|
52
|
+
renderValues: ITabSetRenderValues, // change the values in this object as required
|
|
49
53
|
) => void;
|
|
50
54
|
onModelChange?: (model: Model) => void;
|
|
51
55
|
onExternalDrag?: (event: React.DragEvent<HTMLDivElement>) => undefined | {
|
|
@@ -69,6 +73,9 @@ export interface ILayoutProps {
|
|
|
69
73
|
cursor?: string | undefined
|
|
70
74
|
};
|
|
71
75
|
onRenderDragRect?: DragRectRenderCallback;
|
|
76
|
+
onRenderFloatingTabPlaceholder?: FloatingTabPlaceholderRenderCallback;
|
|
77
|
+
onContextMenu?: NodeMouseEvent;
|
|
78
|
+
onAuxMouseClick?: NodeMouseEvent;
|
|
72
79
|
}
|
|
73
80
|
export interface IFontValues {
|
|
74
81
|
size?: string;
|
|
@@ -114,6 +121,15 @@ export interface IIcons {
|
|
|
114
121
|
more?: React.ReactNode;
|
|
115
122
|
}
|
|
116
123
|
|
|
124
|
+
const defaultIcons = {
|
|
125
|
+
close: <CloseIcon/>,
|
|
126
|
+
closeTabset: <CloseIcon/>,
|
|
127
|
+
popout: <PopoutIcon/>,
|
|
128
|
+
maximize: <MaximizeIcon/>,
|
|
129
|
+
restore: <RestoreIcon/>,
|
|
130
|
+
more: <OverflowIcon/>,
|
|
131
|
+
};
|
|
132
|
+
|
|
117
133
|
export interface ICustomDropDestination {
|
|
118
134
|
rect: Rect;
|
|
119
135
|
callback: CustomDragCallback;
|
|
@@ -140,7 +156,7 @@ export interface ILayoutCallbacks {
|
|
|
140
156
|
getRootDiv(): HTMLDivElement;
|
|
141
157
|
dragStart(
|
|
142
158
|
event: Event | React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement> | undefined,
|
|
143
|
-
dragDivText: string,
|
|
159
|
+
dragDivText: string | undefined,
|
|
144
160
|
node: Node & IDraggable,
|
|
145
161
|
allowDrag: boolean,
|
|
146
162
|
onClick?: (event: Event) => void,
|
|
@@ -157,7 +173,9 @@ export interface ILayoutCallbacks {
|
|
|
157
173
|
styleFont: (style: Record<string, string>) => Record<string, string>;
|
|
158
174
|
setEditingTab(tabNode?: TabNode): void;
|
|
159
175
|
getEditingTab(): TabNode | undefined;
|
|
160
|
-
|
|
176
|
+
getOnRenderFloatingTabPlaceholder(): FloatingTabPlaceholderRenderCallback | undefined;
|
|
177
|
+
showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>): void;
|
|
178
|
+
auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>): void;
|
|
161
179
|
}
|
|
162
180
|
|
|
163
181
|
// Popout windows work in latest browsers based on webkit (Chrome, Opera, Safari, latest Edge) and Firefox. They do
|
|
@@ -207,7 +225,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
207
225
|
/** @hidden @internal */
|
|
208
226
|
private dragRectRendered: boolean = true;
|
|
209
227
|
/** @hidden @internal */
|
|
210
|
-
private dragDivText: string =
|
|
228
|
+
private dragDivText: string | undefined = undefined;
|
|
211
229
|
/** @hidden @internal */
|
|
212
230
|
private dropInfo: DropInfo | undefined;
|
|
213
231
|
/** @hidden @internal */
|
|
@@ -256,8 +274,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
256
274
|
this.findBorderBarSizeRef = React.createRef<HTMLDivElement>();
|
|
257
275
|
this.supportsPopout = props.supportsPopout !== undefined ? props.supportsPopout : defaultSupportsPopout;
|
|
258
276
|
this.popoutURL = props.popoutURL ? props.popoutURL : "popout.html";
|
|
259
|
-
|
|
260
|
-
this.icons = props.closeIcon ? Object.assign({ close: props.closeIcon }, props.icons) : props.icons;
|
|
277
|
+
this.icons = {...defaultIcons, ...props.icons};
|
|
261
278
|
this.firstRender = true;
|
|
262
279
|
|
|
263
280
|
this.state = {
|
|
@@ -275,11 +292,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
275
292
|
/** @hidden @internal */
|
|
276
293
|
styleFont(style: Record<string, string>): Record<string, string> {
|
|
277
294
|
if (this.props.font) {
|
|
278
|
-
if (this.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
295
|
+
if (this.selfRef.current) {
|
|
296
|
+
if (this.props.font.size) {
|
|
297
|
+
this.selfRef.current.style.setProperty("--font-size", this.props.font.size);
|
|
298
|
+
}
|
|
299
|
+
if (this.props.font.family) {
|
|
300
|
+
this.selfRef.current.style.setProperty("--font-family", this.props.font.family);
|
|
301
|
+
}
|
|
283
302
|
}
|
|
284
303
|
if (this.props.font.style) {
|
|
285
304
|
style.fontStyle = this.props.font.style;
|
|
@@ -451,14 +470,14 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
451
470
|
const metrics: ILayoutMetrics = {
|
|
452
471
|
headerBarSize: this.state.calculatedHeaderBarSize,
|
|
453
472
|
tabBarSize: this.state.calculatedTabBarSize,
|
|
454
|
-
borderBarSize: this.state.calculatedBorderBarSize
|
|
473
|
+
borderBarSize: this.state.calculatedBorderBarSize
|
|
455
474
|
};
|
|
456
475
|
this.props.model._setShowHiddenBorder(this.state.showHiddenBorder);
|
|
457
476
|
|
|
458
477
|
this.centerRect = this.props.model._layout(this.state.rect, metrics);
|
|
459
478
|
|
|
460
479
|
this.renderBorder(this.props.model.getBorderSet(), borderComponents, tabComponents, floatingWindows, splitterComponents);
|
|
461
|
-
this.renderChildren(this.props.model.getRoot(), tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
480
|
+
this.renderChildren("", this.props.model.getRoot(), tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
462
481
|
|
|
463
482
|
if (this.edgesShown) {
|
|
464
483
|
this.repositionEdges(this.state.rect)
|
|
@@ -536,10 +555,12 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
536
555
|
/** @hidden @internal */
|
|
537
556
|
renderBorder(borderSet: BorderSet, borderComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
538
557
|
for (const border of borderSet.getBorders()) {
|
|
558
|
+
const borderPath = `/border/${border.getLocation().getName()}`;
|
|
539
559
|
if (border.isShowing()) {
|
|
540
560
|
borderComponents.push(
|
|
541
561
|
<BorderTabSet
|
|
542
|
-
key={
|
|
562
|
+
key={`border_${border.getLocation().getName()}`}
|
|
563
|
+
path={borderPath}
|
|
543
564
|
border={border}
|
|
544
565
|
layout={this}
|
|
545
566
|
iconFactory={this.props.iconFactory}
|
|
@@ -549,10 +570,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
549
570
|
);
|
|
550
571
|
const drawChildren = border._getDrawChildren();
|
|
551
572
|
let i = 0;
|
|
573
|
+
let tabCount = 0;
|
|
552
574
|
for (const child of drawChildren) {
|
|
553
575
|
if (child instanceof SplitterNode) {
|
|
554
|
-
|
|
576
|
+
let path = borderPath + "/s";
|
|
577
|
+
splitterComponents.push(<Splitter key={child.getId()} layout={this} node={child} path={path} />);
|
|
555
578
|
} else if (child instanceof TabNode) {
|
|
579
|
+
let path = borderPath + "/t" + tabCount++;
|
|
556
580
|
if (this.supportsPopout && child.isFloating()) {
|
|
557
581
|
const rect = this._getScreenRect(child);
|
|
558
582
|
floatingWindows.push(
|
|
@@ -568,9 +592,19 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
568
592
|
<FloatingWindowTab layout={this} node={child} factory={this.props.factory} />
|
|
569
593
|
</FloatingWindow>
|
|
570
594
|
);
|
|
571
|
-
tabComponents[child.getId()] = <TabFloating key={child.getId()}
|
|
595
|
+
tabComponents[child.getId()] = <TabFloating key={child.getId()}
|
|
596
|
+
layout={this}
|
|
597
|
+
path={path}
|
|
598
|
+
node={child}
|
|
599
|
+
selected={i === border.getSelected()
|
|
600
|
+
} />;
|
|
572
601
|
} else {
|
|
573
|
-
tabComponents[child.getId()] = <Tab key={child.getId()}
|
|
602
|
+
tabComponents[child.getId()] = <Tab key={child.getId()}
|
|
603
|
+
layout={this}
|
|
604
|
+
path={path}
|
|
605
|
+
node={child}
|
|
606
|
+
selected={i === border.getSelected()}
|
|
607
|
+
factory={this.props.factory} />;
|
|
574
608
|
}
|
|
575
609
|
}
|
|
576
610
|
i++;
|
|
@@ -580,16 +614,22 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
580
614
|
}
|
|
581
615
|
|
|
582
616
|
/** @hidden @internal */
|
|
583
|
-
renderChildren(node: RowNode | TabSetNode, tabSetComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
617
|
+
renderChildren(path: string, node: RowNode | TabSetNode, tabSetComponents: React.ReactNode[], tabComponents: Record<string, React.ReactNode>, floatingWindows: React.ReactNode[], splitterComponents: React.ReactNode[]) {
|
|
584
618
|
const drawChildren = node._getDrawChildren();
|
|
619
|
+
let splitterCount = 0;
|
|
620
|
+
let tabCount = 0;
|
|
621
|
+
let rowCount = 0;
|
|
585
622
|
|
|
586
623
|
for (const child of drawChildren!) {
|
|
587
624
|
if (child instanceof SplitterNode) {
|
|
588
|
-
|
|
625
|
+
const newPath = path + "/s" + (splitterCount++);
|
|
626
|
+
splitterComponents.push(<Splitter key={child.getId()} layout={this} path={newPath} node={child} />);
|
|
589
627
|
} else if (child instanceof TabSetNode) {
|
|
590
|
-
|
|
591
|
-
|
|
628
|
+
const newPath = path + "/ts" + (rowCount++);
|
|
629
|
+
tabSetComponents.push(<TabSet key={child.getId()} layout={this} path={newPath} node={child} iconFactory={this.props.iconFactory} titleFactory={this.props.titleFactory} icons={this.icons} />);
|
|
630
|
+
this.renderChildren(newPath, child, tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
592
631
|
} else if (child instanceof TabNode) {
|
|
632
|
+
const newPath = path + "/t" + (tabCount++);
|
|
593
633
|
const selectedTab = child.getParent()!.getChildren()[(child.getParent() as TabSetNode).getSelected()];
|
|
594
634
|
if (selectedTab === undefined) {
|
|
595
635
|
// this should not happen!
|
|
@@ -610,13 +650,14 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
610
650
|
<FloatingWindowTab layout={this} node={child} factory={this.props.factory} />
|
|
611
651
|
</FloatingWindow>
|
|
612
652
|
);
|
|
613
|
-
tabComponents[child.getId()] = <TabFloating key={child.getId()} layout={this} node={child} selected={child === selectedTab} />;
|
|
653
|
+
tabComponents[child.getId()] = <TabFloating key={child.getId()} layout={this} path={newPath} node={child} selected={child === selectedTab} />;
|
|
614
654
|
} else {
|
|
615
|
-
tabComponents[child.getId()] = <Tab key={child.getId()} layout={this} node={child} selected={child === selectedTab} factory={this.props.factory} />;
|
|
655
|
+
tabComponents[child.getId()] = <Tab key={child.getId()} layout={this} path={newPath} node={child} selected={child === selectedTab} factory={this.props.factory} />;
|
|
616
656
|
}
|
|
617
657
|
} else {
|
|
618
658
|
// is row
|
|
619
|
-
|
|
659
|
+
const newPath = path + ((child.getOrientation() === Orientation.HORZ) ? "/r" : "/c") + (rowCount++);
|
|
660
|
+
this.renderChildren(newPath, child as RowNode, tabSetComponents, tabComponents, floatingWindows, splitterComponents);
|
|
620
661
|
}
|
|
621
662
|
}
|
|
622
663
|
}
|
|
@@ -661,7 +702,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
661
702
|
* @param json the json for the new tab node
|
|
662
703
|
* @param onDrop a callback to call when the drag is complete (node and event will be undefined if the drag was cancelled)
|
|
663
704
|
*/
|
|
664
|
-
addTabWithDragAndDrop(dragText: string, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
705
|
+
addTabWithDragAndDrop(dragText: string | undefined, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
665
706
|
this.fnNewNodeDropped = onDrop;
|
|
666
707
|
this.newTabJson = json;
|
|
667
708
|
this.dragStart(undefined, dragText, TabNode._fromJson(json, this.props.model, false), true, undefined, undefined);
|
|
@@ -675,7 +716,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
675
716
|
* @param json the json for the new tab node
|
|
676
717
|
* @param onDrop a callback to call when the drag is complete (node and event will be undefined if the drag was cancelled)
|
|
677
718
|
*/
|
|
678
|
-
addTabWithDragAndDropIndirect(dragText: string, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
719
|
+
addTabWithDragAndDropIndirect(dragText: string | undefined, json: IJsonTabNode, onDrop?: (node?: Node, event?: Event) => void) {
|
|
679
720
|
this.fnNewNodeDropped = onDrop;
|
|
680
721
|
this.newTabJson = json;
|
|
681
722
|
|
|
@@ -683,7 +724,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
683
724
|
|
|
684
725
|
this.dragDivText = dragText;
|
|
685
726
|
this.dragDiv = this.currentDocument!.createElement("div");
|
|
686
|
-
this.dragDiv.className = this.getClassName(
|
|
727
|
+
this.dragDiv.className = this.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT);
|
|
687
728
|
this.dragDiv.addEventListener("mousedown", this.onDragDivMouseDown);
|
|
688
729
|
this.dragDiv.addEventListener("touchstart", this.onDragDivMouseDown);
|
|
689
730
|
|
|
@@ -694,6 +735,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
694
735
|
const domRect = this.dragDiv.getBoundingClientRect();
|
|
695
736
|
const r = new Rect(0, 0, domRect?.width, domRect?.height);
|
|
696
737
|
r.centerInRect(this.state.rect);
|
|
738
|
+
this.dragDiv.setAttribute("data-layout-path", "/drag-rectangle");
|
|
697
739
|
this.dragDiv.style.left = r.x + "px";
|
|
698
740
|
this.dragDiv.style.top = r.y + "px";
|
|
699
741
|
}
|
|
@@ -767,7 +809,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
767
809
|
/** @hidden @internal */
|
|
768
810
|
dragStart = (
|
|
769
811
|
event: Event | React.MouseEvent<HTMLDivElement, MouseEvent> | React.TouchEvent<HTMLDivElement> | React.DragEvent<HTMLDivElement> | undefined,
|
|
770
|
-
dragDivText: string,
|
|
812
|
+
dragDivText: string | undefined,
|
|
771
813
|
node: Node & IDraggable,
|
|
772
814
|
allowDrag: boolean,
|
|
773
815
|
onClick?: (event: Event) => void,
|
|
@@ -783,11 +825,24 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
783
825
|
};
|
|
784
826
|
|
|
785
827
|
/** @hidden @internal */
|
|
786
|
-
dragRectRender = (text: String, node?: Node, json?: IJsonTabNode, onRendered?: () => void) => {
|
|
787
|
-
let content: React.ReactElement | undefined
|
|
828
|
+
dragRectRender = (text: String | undefined, node?: Node, json?: IJsonTabNode, onRendered?: () => void) => {
|
|
829
|
+
let content: React.ReactElement | undefined;
|
|
830
|
+
|
|
831
|
+
if (text !== undefined) {
|
|
832
|
+
content = <div style={{ whiteSpace: "pre" }}>{text.replace("<br>", "\n")}</div>;
|
|
833
|
+
} else {
|
|
834
|
+
if (node && node instanceof TabNode) {
|
|
835
|
+
content = (<TabButtonStamp
|
|
836
|
+
node={node}
|
|
837
|
+
layout={this}
|
|
838
|
+
iconFactory={this.props.iconFactory}
|
|
839
|
+
titleFactory={this.props.titleFactory}
|
|
840
|
+
/>);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
788
843
|
|
|
789
844
|
if (this.props.onRenderDragRect !== undefined) {
|
|
790
|
-
const customContent = this.props.onRenderDragRect(
|
|
845
|
+
const customContent = this.props.onRenderDragRect(content, node, json);
|
|
791
846
|
if (customContent !== undefined) {
|
|
792
847
|
content = customContent;
|
|
793
848
|
}
|
|
@@ -820,6 +875,7 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
820
875
|
if (this.dragDiv == null) {
|
|
821
876
|
this.dragDiv = this.currentDocument!.createElement("div");
|
|
822
877
|
this.dragDiv.className = this.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT);
|
|
878
|
+
this.dragDiv.setAttribute("data-layout-path", "/drag-rectangle");
|
|
823
879
|
this.dragRectRender(this.dragDivText, this.dragNode, this.newTabJson);
|
|
824
880
|
|
|
825
881
|
rootdiv.appendChild(this.dragDiv);
|
|
@@ -867,62 +923,13 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
867
923
|
|
|
868
924
|
let dropInfo = this.props.model._findDropTargetNode(this.dragNode!, pos.x, pos.y);
|
|
869
925
|
if (dropInfo) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
this.customDrop = undefined;
|
|
873
|
-
|
|
874
|
-
const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
|
|
875
|
-
if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
|
|
876
|
-
const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
|
|
877
|
-
const tabRect = selected?.getRect()
|
|
878
|
-
|
|
879
|
-
if (selected && tabRect?.contains(pos.x, pos.y)) {
|
|
880
|
-
let customDrop: ICustomDropDestination | undefined = undefined;
|
|
881
|
-
|
|
882
|
-
try {
|
|
883
|
-
const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location, () => this.onDragMove(event));
|
|
884
|
-
|
|
885
|
-
if (dest) {
|
|
886
|
-
customDrop = {
|
|
887
|
-
rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
|
|
888
|
-
callback: dest.callback,
|
|
889
|
-
invalidated: dest.invalidated,
|
|
890
|
-
dragging: dragging,
|
|
891
|
-
over: selected,
|
|
892
|
-
x: pos.x - tabRect.x,
|
|
893
|
-
y: pos.y - tabRect.y,
|
|
894
|
-
location: dropInfo.location,
|
|
895
|
-
cursor: dest.cursor
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
} catch (e) {
|
|
899
|
-
console.error(e)
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
if (customDrop?.callback === currentCallback) {
|
|
903
|
-
invalidated = undefined;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
this.customDrop = customDrop;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
this.dropInfo = dropInfo;
|
|
911
|
-
this.outlineDiv!.className = this.getClassName(this.customDrop ? "flexlayout__outline_rect" : dropInfo.className);
|
|
912
|
-
|
|
913
|
-
if (this.customDrop) {
|
|
914
|
-
this.customDrop.rect.positionElement(this.outlineDiv!);
|
|
926
|
+
if (this.props.onTabDrag) {
|
|
927
|
+
this.handleCustomTabDrag(dropInfo, pos, event);
|
|
915
928
|
} else {
|
|
929
|
+
this.dropInfo = dropInfo;
|
|
930
|
+
this.outlineDiv!.className = this.getClassName(dropInfo.className);
|
|
916
931
|
dropInfo.rect.positionElement(this.outlineDiv!);
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
DragDrop.instance.setGlassCursorOverride(this.customDrop?.cursor);
|
|
920
|
-
this.outlineDiv!.style.visibility = "visible";
|
|
921
|
-
|
|
922
|
-
try {
|
|
923
|
-
invalidated?.();
|
|
924
|
-
} catch (e) {
|
|
925
|
-
console.error(e);
|
|
932
|
+
this.outlineDiv!.style.visibility = "visible";
|
|
926
933
|
}
|
|
927
934
|
}
|
|
928
935
|
};
|
|
@@ -943,6 +950,10 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
943
950
|
try {
|
|
944
951
|
const { callback, dragging, over, x, y, location } = this.customDrop;
|
|
945
952
|
callback(dragging, over, x, y, location);
|
|
953
|
+
if (this.fnNewNodeDropped != null) {
|
|
954
|
+
this.fnNewNodeDropped();
|
|
955
|
+
this.fnNewNodeDropped = undefined;
|
|
956
|
+
}
|
|
946
957
|
} catch (e) {
|
|
947
958
|
console.error(e)
|
|
948
959
|
}
|
|
@@ -961,6 +972,67 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
961
972
|
this.setState({ showHiddenBorder: DockLocation.CENTER });
|
|
962
973
|
};
|
|
963
974
|
|
|
975
|
+
/** @hidden @internal */
|
|
976
|
+
private handleCustomTabDrag(dropInfo: DropInfo, pos: { x: number; y: number; }, event: React.MouseEvent<Element, MouseEvent>) {
|
|
977
|
+
let invalidated = this.customDrop?.invalidated;
|
|
978
|
+
const currentCallback = this.customDrop?.callback;
|
|
979
|
+
this.customDrop = undefined;
|
|
980
|
+
|
|
981
|
+
const dragging = this.newTabJson || (this.dragNode instanceof TabNode ? this.dragNode : undefined);
|
|
982
|
+
if (dragging && (dropInfo.node instanceof TabSetNode || dropInfo.node instanceof BorderNode) && dropInfo.index === -1) {
|
|
983
|
+
const selected = dropInfo.node.getSelectedNode() as TabNode | undefined;
|
|
984
|
+
const tabRect = selected?.getRect();
|
|
985
|
+
|
|
986
|
+
if (selected && tabRect?.contains(pos.x, pos.y)) {
|
|
987
|
+
let customDrop: ICustomDropDestination | undefined = undefined;
|
|
988
|
+
|
|
989
|
+
try {
|
|
990
|
+
const dest = this.onTabDrag(dragging, selected, pos.x - tabRect.x, pos.y - tabRect.y, dropInfo.location, () => this.onDragMove(event));
|
|
991
|
+
|
|
992
|
+
if (dest) {
|
|
993
|
+
customDrop = {
|
|
994
|
+
rect: new Rect(dest.x + tabRect.x, dest.y + tabRect.y, dest.width, dest.height),
|
|
995
|
+
callback: dest.callback,
|
|
996
|
+
invalidated: dest.invalidated,
|
|
997
|
+
dragging: dragging,
|
|
998
|
+
over: selected,
|
|
999
|
+
x: pos.x - tabRect.x,
|
|
1000
|
+
y: pos.y - tabRect.y,
|
|
1001
|
+
location: dropInfo.location,
|
|
1002
|
+
cursor: dest.cursor
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
} catch (e) {
|
|
1006
|
+
console.error(e);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if (customDrop?.callback === currentCallback) {
|
|
1010
|
+
invalidated = undefined;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
this.customDrop = customDrop;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
this.dropInfo = dropInfo;
|
|
1018
|
+
this.outlineDiv!.className = this.getClassName(this.customDrop ? CLASSES.FLEXLAYOUT__OUTLINE_RECT : dropInfo.className);
|
|
1019
|
+
|
|
1020
|
+
if (this.customDrop) {
|
|
1021
|
+
this.customDrop.rect.positionElement(this.outlineDiv!);
|
|
1022
|
+
} else {
|
|
1023
|
+
dropInfo.rect.positionElement(this.outlineDiv!);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
DragDrop.instance.setGlassCursorOverride(this.customDrop?.cursor);
|
|
1027
|
+
this.outlineDiv!.style.visibility = "visible";
|
|
1028
|
+
|
|
1029
|
+
try {
|
|
1030
|
+
invalidated?.();
|
|
1031
|
+
} catch (e) {
|
|
1032
|
+
console.error(e);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
964
1036
|
/** @hidden @internal */
|
|
965
1037
|
onDragEnter(event: React.DragEvent<HTMLDivElement>) {
|
|
966
1038
|
// DragDrop keeps track of number of dragenters minus the number of
|
|
@@ -1125,6 +1197,25 @@ export class Layout extends React.Component<ILayoutProps, ILayoutState> {
|
|
|
1125
1197
|
}
|
|
1126
1198
|
return message;
|
|
1127
1199
|
}
|
|
1200
|
+
|
|
1201
|
+
/** @hidden @internal */
|
|
1202
|
+
getOnRenderFloatingTabPlaceholder() {
|
|
1203
|
+
return this.props.onRenderFloatingTabPlaceholder;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/** @hidden @internal */
|
|
1207
|
+
showContextMenu(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
|
|
1208
|
+
if (this.props.onContextMenu) {
|
|
1209
|
+
this.props.onContextMenu(node, event);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/** @hidden @internal */
|
|
1214
|
+
auxMouseClick(node: TabNode | TabSetNode | BorderNode, event: React.MouseEvent<HTMLElement, MouseEvent>) {
|
|
1215
|
+
if (this.props.onAuxMouseClick) {
|
|
1216
|
+
this.props.onAuxMouseClick(node, event);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1128
1219
|
}
|
|
1129
1220
|
|
|
1130
1221
|
// wrapper round the drag rect renderer that can call
|
package/src/view/Splitter.tsx
CHANGED
|
@@ -13,11 +13,12 @@ import { ILayoutCallbacks } from "./Layout";
|
|
|
13
13
|
export interface ISplitterProps {
|
|
14
14
|
layout: ILayoutCallbacks;
|
|
15
15
|
node: SplitterNode;
|
|
16
|
+
path: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
/** @hidden @internal */
|
|
19
20
|
export const Splitter = (props: ISplitterProps) => {
|
|
20
|
-
const { layout, node } = props;
|
|
21
|
+
const { layout, node, path } = props;
|
|
21
22
|
|
|
22
23
|
const pBounds = React.useRef<number[]>([]);
|
|
23
24
|
const outlineDiv = React.useRef<HTMLDivElement | undefined>(undefined);
|
|
@@ -132,6 +133,7 @@ export const Splitter = (props: ISplitterProps) => {
|
|
|
132
133
|
if (extra === 0) {
|
|
133
134
|
return (<div
|
|
134
135
|
style={style}
|
|
136
|
+
data-layout-path={path}
|
|
135
137
|
className={className}
|
|
136
138
|
onTouchStart={onMouseDown}
|
|
137
139
|
onMouseDown={onMouseDown}>
|
|
@@ -156,6 +158,7 @@ export const Splitter = (props: ISplitterProps) => {
|
|
|
156
158
|
return (
|
|
157
159
|
<div
|
|
158
160
|
style={style}
|
|
161
|
+
data-layout-path={path}
|
|
159
162
|
className={className}>
|
|
160
163
|
<div
|
|
161
164
|
style={style2}
|
package/src/view/Tab.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { ILayoutCallbacks } from "./Layout";
|
|
|
8
8
|
import { ErrorBoundary } from "./ErrorBoundary";
|
|
9
9
|
import { I18nLabel } from "../I18nLabel";
|
|
10
10
|
import { BorderNode } from "..";
|
|
11
|
+
import { hideElement } from "./Utils";
|
|
11
12
|
|
|
12
13
|
/** @hidden @internal */
|
|
13
14
|
export interface ITabProps {
|
|
@@ -15,11 +16,12 @@ export interface ITabProps {
|
|
|
15
16
|
selected: boolean;
|
|
16
17
|
node: TabNode;
|
|
17
18
|
factory: (node: TabNode) => React.ReactNode;
|
|
19
|
+
path: string;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/** @hidden @internal */
|
|
21
23
|
export const Tab = (props: ITabProps) => {
|
|
22
|
-
const { layout, selected, node, factory } = props;
|
|
24
|
+
const { layout, selected, node, factory, path } = props;
|
|
23
25
|
const [renderComponent, setRenderComponent] = React.useState<boolean>(!props.node.isEnableRenderOnDemand() || props.selected);
|
|
24
26
|
|
|
25
27
|
React.useLayoutEffect(() => {
|
|
@@ -40,15 +42,17 @@ export const Tab = (props: ITabProps) => {
|
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
const cm = layout.getClassName;
|
|
45
|
+
const useVisibility = node.getModel().isUseVisibility();
|
|
43
46
|
|
|
44
47
|
const parentNode = node.getParent() as TabSetNode | BorderNode;
|
|
45
|
-
const style: Record<string, any> = node._styleWithPosition(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
const style: Record<string, any> = node._styleWithPosition();
|
|
49
|
+
if (!selected) {
|
|
50
|
+
hideElement(style, useVisibility);
|
|
51
|
+
}
|
|
48
52
|
|
|
49
53
|
if (parentNode instanceof TabSetNode) {
|
|
50
54
|
if (node.getModel().getMaximizedTabset() !== undefined && !parentNode.isMaximized()) {
|
|
51
|
-
style
|
|
55
|
+
hideElement(style, useVisibility);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -64,10 +68,17 @@ export const Tab = (props: ITabProps) => {
|
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
return (
|
|
67
|
-
<div
|
|
71
|
+
<div
|
|
72
|
+
className={className}
|
|
73
|
+
data-layout-path={path}
|
|
74
|
+
onMouseDown={onMouseDown}
|
|
75
|
+
onTouchStart={onMouseDown}
|
|
76
|
+
style={style}>
|
|
68
77
|
<ErrorBoundary message={props.layout.i18nName(I18nLabel.Error_rendering_component)}>
|
|
69
78
|
<Fragment>{child}</Fragment>
|
|
70
79
|
</ErrorBoundary>
|
|
71
80
|
</div>
|
|
72
81
|
);
|
|
73
82
|
};
|
|
83
|
+
|
|
84
|
+
|