flexlayout-react 0.8.7 → 0.8.9
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 +9 -0
- package/README.md +23 -14
- package/declarations/model/TabNode.d.ts +1 -0
- package/declarations/view/Layout.d.ts +1 -1
- package/dist/flexlayout.js +8 -8
- package/dist/flexlayout_min.js +1 -1
- package/lib/model/TabNode.js +4 -1
- package/lib/model/TabNode.js.map +1 -1
- package/lib/view/BorderButton.js +1 -3
- package/lib/view/BorderButton.js.map +1 -1
- package/lib/view/BorderTabSet.js +4 -4
- package/lib/view/BorderTabSet.js.map +1 -1
- package/lib/view/Layout.js +1 -1
- package/lib/view/PopupMenu.js +14 -1
- package/lib/view/PopupMenu.js.map +1 -1
- package/lib/view/TabButton.js +1 -3
- package/lib/view/TabButton.js.map +1 -1
- package/lib/view/TabOverflowHook.js +19 -13
- package/lib/view/TabOverflowHook.js.map +1 -1
- package/lib/view/TabSet.js +4 -4
- package/lib/view/TabSet.js.map +1 -1
- package/package.json +1 -2
- package/src/model/TabNode.ts +5 -1
- package/src/view/BorderButton.tsx +1 -2
- package/src/view/BorderTabSet.tsx +4 -4
- package/src/view/Layout.tsx +1 -1
- package/src/view/PopupMenu.tsx +18 -0
- package/src/view/TabButton.tsx +1 -2
- package/src/view/TabOverflowHook.tsx +21 -13
- package/src/view/TabSet.tsx +4 -4
- package/style/_themes.scss +1 -1
- package/style/combined.css +1053 -1053
- package/style/dark.css +705 -705
- package/style/gray.css +708 -708
- package/style/light.css +682 -682
- package/style/rounded.css +721 -721
- package/style/underline.css +711 -711
|
@@ -35,7 +35,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
|
|
|
35
35
|
border.setTabHeaderRect(layout.getBoundingClientRect(selfRef.current!));
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel,
|
|
38
|
+
const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } =
|
|
39
39
|
useTabOverflow(layout, border, Orientation.flip(border.getOrientation()), tabStripInnerRef, miniScrollRef,
|
|
40
40
|
layout.getClassName(CLASSES.FLEXLAYOUT__BORDER_BUTTON)
|
|
41
41
|
);
|
|
@@ -132,7 +132,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
if (stickyButtons.length > 0) {
|
|
135
|
-
if (
|
|
135
|
+
if (isDockStickyButtons) {
|
|
136
136
|
buttons = [...stickyButtons, ...buttons];
|
|
137
137
|
} else {
|
|
138
138
|
tabButtons.push(<div
|
|
@@ -147,7 +147,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
if (
|
|
150
|
+
if (isShowHiddenTabs) {
|
|
151
151
|
const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip);
|
|
152
152
|
let overflowContent;
|
|
153
153
|
if (typeof icons.more === "function") {
|
|
@@ -157,7 +157,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
|
|
|
157
157
|
} else {
|
|
158
158
|
overflowContent = (<>
|
|
159
159
|
{icons.more}
|
|
160
|
-
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length}</div>
|
|
160
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length>0?hiddenTabs.length: ""}</div>
|
|
161
161
|
</>);
|
|
162
162
|
}
|
|
163
163
|
buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,
|
package/src/view/Layout.tsx
CHANGED
|
@@ -1228,7 +1228,7 @@ export class LayoutInternal extends React.Component<ILayoutInternalProps, ILayou
|
|
|
1228
1228
|
// *************************** End Drag Drop *************************************
|
|
1229
1229
|
}
|
|
1230
1230
|
|
|
1231
|
-
export const FlexLayoutVersion = "0.8.
|
|
1231
|
+
export const FlexLayoutVersion = "0.8.9";
|
|
1232
1232
|
|
|
1233
1233
|
export type DragRectRenderCallback = (
|
|
1234
1234
|
content: React.ReactNode | undefined,
|
package/src/view/PopupMenu.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { LayoutInternal } from "./Layout";
|
|
|
5
5
|
import { TabButtonStamp } from "./TabButtonStamp";
|
|
6
6
|
import { TabSetNode } from "../model/TabSetNode";
|
|
7
7
|
import { BorderNode } from "../model/BorderNode";
|
|
8
|
+
import { useEffect, useRef } from "react";
|
|
8
9
|
|
|
9
10
|
/** @internal */
|
|
10
11
|
export function showPopup(
|
|
@@ -86,6 +87,14 @@ interface IPopupMenuProps {
|
|
|
86
87
|
/** @internal */
|
|
87
88
|
const PopupMenu = (props: IPopupMenuProps) => {
|
|
88
89
|
const { parentNode, items, onHide, onSelect, classNameMapper, layout } = props;
|
|
90
|
+
const divRef = useRef<HTMLDivElement>(null);
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
// Set focus when the component mounts
|
|
94
|
+
if (divRef.current) {
|
|
95
|
+
divRef.current.focus();
|
|
96
|
+
}
|
|
97
|
+
}, []);
|
|
89
98
|
|
|
90
99
|
const onItemClick = (item: { index: number; node: TabNode }, event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
|
91
100
|
onSelect(item);
|
|
@@ -106,6 +115,12 @@ const PopupMenu = (props: IPopupMenuProps) => {
|
|
|
106
115
|
layout.clearDragMain();
|
|
107
116
|
};
|
|
108
117
|
|
|
118
|
+
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
119
|
+
if (event.key === "Escape") {
|
|
120
|
+
onHide();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
109
124
|
const itemElements = items.map((item, i) => {
|
|
110
125
|
let classes = classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU_ITEM);
|
|
111
126
|
if (parentNode.getSelected() === item.index) {
|
|
@@ -131,6 +146,9 @@ const PopupMenu = (props: IPopupMenuProps) => {
|
|
|
131
146
|
|
|
132
147
|
return (
|
|
133
148
|
<div className={classNameMapper(CLASSES.FLEXLAYOUT__POPUP_MENU)}
|
|
149
|
+
ref={divRef}
|
|
150
|
+
tabIndex={0} // Make div focusable
|
|
151
|
+
onKeyDown={handleKeyDown}
|
|
134
152
|
data-layout-path="/popup-menu"
|
|
135
153
|
>
|
|
136
154
|
{itemElements}
|
package/src/view/TabButton.tsx
CHANGED
|
@@ -93,8 +93,7 @@ export const TabButton = (props: ITabButtonProps) => {
|
|
|
93
93
|
const onClose = (event: React.MouseEvent<HTMLElement>) => {
|
|
94
94
|
if (isClosable()) {
|
|
95
95
|
layout.doAction(Actions.deleteTab(node.getId()));
|
|
96
|
-
|
|
97
|
-
onClick();
|
|
96
|
+
event.stopPropagation();
|
|
98
97
|
}
|
|
99
98
|
};
|
|
100
99
|
|
|
@@ -17,7 +17,8 @@ export const useTabOverflow = (
|
|
|
17
17
|
tabClassName: string
|
|
18
18
|
) => {
|
|
19
19
|
const [hiddenTabs, setHiddenTabs] = React.useState<number[]>([]);
|
|
20
|
-
const [
|
|
20
|
+
const [isShowHiddenTabs, setShowHiddenTabs] = React.useState<boolean>(false);
|
|
21
|
+
const [isDockStickyButtons, setDockStickyButtons] = React.useState<boolean>(false);
|
|
21
22
|
|
|
22
23
|
const selfRef = React.useRef<HTMLDivElement | null>(null);
|
|
23
24
|
const userControlledPositionRef = React.useRef<boolean>(false);
|
|
@@ -27,27 +28,27 @@ export const useTabOverflow = (
|
|
|
27
28
|
const repositioningRef = React.useRef<boolean>(false);
|
|
28
29
|
hiddenTabsRef.current = hiddenTabs;
|
|
29
30
|
|
|
30
|
-
// if node changes (new model) then reset scroll to 0
|
|
31
|
-
React.
|
|
31
|
+
// if node id changes (new model) then reset scroll to 0
|
|
32
|
+
React.useLayoutEffect(() => {
|
|
32
33
|
if (tabStripRef.current) {
|
|
33
34
|
setScrollPosition(0);
|
|
34
35
|
}
|
|
35
|
-
}, [node]);
|
|
36
|
+
}, [node.getId()]);
|
|
36
37
|
|
|
37
38
|
// if selected node or tabset/border rectangle change then unset usercontrolled (so selected tab will be kept in view)
|
|
38
|
-
React.
|
|
39
|
+
React.useLayoutEffect(() => {
|
|
39
40
|
userControlledPositionRef.current = false;
|
|
40
41
|
}, [node.getSelectedNode(), node.getRect().width, node.getRect().height]);
|
|
41
42
|
|
|
42
|
-
React.
|
|
43
|
+
React.useLayoutEffect(() => {
|
|
43
44
|
checkForOverflow(); // if tabs + sticky buttons length > scroll area => move sticky buttons to right buttons
|
|
44
45
|
|
|
45
46
|
if (userControlledPositionRef.current === false) {
|
|
46
47
|
scrollIntoView();
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
updateHiddenTabs();
|
|
50
50
|
updateScrollMetrics();
|
|
51
|
+
updateHiddenTabs();
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
function scrollIntoView() {
|
|
@@ -57,12 +58,12 @@ export const useTabOverflow = (
|
|
|
57
58
|
const selectedRect = selectedTabNode.getTabRect()!;
|
|
58
59
|
|
|
59
60
|
let shift = getNear(stripRect) - getNear(selectedRect);
|
|
60
|
-
if (shift >
|
|
61
|
+
if (shift > 0 || getSize(selectedRect) > getSize(stripRect)) {
|
|
61
62
|
setScrollPosition(getScrollPosition(tabStripRef.current) - shift);
|
|
62
63
|
repositioningRef.current = true; // prevent onScroll setting userControlledPosition
|
|
63
64
|
} else {
|
|
64
65
|
shift = getFar(selectedRect) - getFar(stripRect);
|
|
65
|
-
if (shift >
|
|
66
|
+
if (shift > 0) {
|
|
66
67
|
setScrollPosition(getScrollPosition(tabStripRef.current) + shift);
|
|
67
68
|
repositioningRef.current = true;
|
|
68
69
|
}
|
|
@@ -108,6 +109,13 @@ export const useTabOverflow = (
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
const updateHiddenTabs = () => {
|
|
112
|
+
const newHiddenTabs = findHiddenTabs();
|
|
113
|
+
const showHidden = newHiddenTabs.length > 0;
|
|
114
|
+
|
|
115
|
+
if (showHidden !== isShowHiddenTabs) {
|
|
116
|
+
setShowHiddenTabs(showHidden);
|
|
117
|
+
}
|
|
118
|
+
|
|
111
119
|
if (updateHiddenTabsTimerRef.current === undefined) {
|
|
112
120
|
// throttle updates to prevent Maximum update depth exceeded error
|
|
113
121
|
updateHiddenTabsTimerRef.current = setTimeout(() => {
|
|
@@ -177,10 +185,10 @@ export const useTabOverflow = (
|
|
|
177
185
|
const strip = tabStripRef.current;
|
|
178
186
|
const tabContainer = strip.firstElementChild!;
|
|
179
187
|
|
|
180
|
-
const offset =
|
|
188
|
+
const offset = isDockStickyButtons ? 10 : 0; // prevents flashing, after sticky buttons docked set, must be 10 pixels smaller before unsetting
|
|
181
189
|
const dock = (getElementSize(tabContainer) + offset) > getElementSize(tabStripRef.current);
|
|
182
|
-
if (dock !==
|
|
183
|
-
|
|
190
|
+
if (dock !== isDockStickyButtons) {
|
|
191
|
+
setDockStickyButtons(dock);
|
|
184
192
|
}
|
|
185
193
|
}
|
|
186
194
|
}
|
|
@@ -289,7 +297,7 @@ export const useTabOverflow = (
|
|
|
289
297
|
}
|
|
290
298
|
}
|
|
291
299
|
|
|
292
|
-
return { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel,
|
|
300
|
+
return { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs };
|
|
293
301
|
};
|
|
294
302
|
|
|
295
303
|
function arraysEqual(arr1: number[], arr2: number[]) {
|
package/src/view/TabSet.tsx
CHANGED
|
@@ -51,7 +51,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
// this must be after the useEffect, so the node rect is already set (else window popin will not position tabs correctly)
|
|
54
|
-
const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel,
|
|
54
|
+
const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } =
|
|
55
55
|
useTabOverflow(layout, node, Orientation.HORZ, tabStripInnerRef, miniScrollRef,
|
|
56
56
|
layout.getClassName(CLASSES.FLEXLAYOUT__TAB_BUTTON));
|
|
57
57
|
|
|
@@ -186,7 +186,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
if (stickyButtons.length > 0) {
|
|
189
|
-
if (!node.isEnableTabWrap() && (
|
|
189
|
+
if (!node.isEnableTabWrap() && (isDockStickyButtons || isTabStretch)) {
|
|
190
190
|
buttons = [...stickyButtons, ...buttons];
|
|
191
191
|
} else {
|
|
192
192
|
tabs.push(<div
|
|
@@ -202,7 +202,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
if (!node.isEnableTabWrap()) {
|
|
205
|
-
if (
|
|
205
|
+
if (isShowHiddenTabs) {
|
|
206
206
|
const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip);
|
|
207
207
|
let overflowContent;
|
|
208
208
|
if (typeof icons.more === "function") {
|
|
@@ -211,7 +211,7 @@ export const TabSet = (props: ITabSetProps) => {
|
|
|
211
211
|
} else {
|
|
212
212
|
overflowContent = (<>
|
|
213
213
|
{icons.more}
|
|
214
|
-
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length}</div>
|
|
214
|
+
<div className={cm(CLASSES.FLEXLAYOUT__TAB_BUTTON_OVERFLOW_COUNT)}>{hiddenTabs.length>0?hiddenTabs.length: ""}</div>
|
|
215
215
|
</>);
|
|
216
216
|
}
|
|
217
217
|
buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,
|
package/style/_themes.scss
CHANGED
|
@@ -559,7 +559,7 @@
|
|
|
559
559
|
--color-border-tab-unselected: gray;
|
|
560
560
|
--color-border-tab-unselected-background: #d3d4e745;
|
|
561
561
|
|
|
562
|
-
--color-splitter:
|
|
562
|
+
--color-splitter: var(--color-background);
|
|
563
563
|
--color-splitter-hover: var(--color-2);
|
|
564
564
|
--color-splitter-drag: var(--color-2);
|
|
565
565
|
|