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.
@@ -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, isTabOverflow } =
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 (isTabOverflow) {
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 (hiddenTabs.length > 0) {
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,
@@ -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.7";
1231
+ export const FlexLayoutVersion = "0.8.9";
1232
1232
 
1233
1233
  export type DragRectRenderCallback = (
1234
1234
  content: React.ReactNode | undefined,
@@ -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}
@@ -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
- } else {
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 [isTabOverflow, setTabOverflow] = React.useState<boolean>(false);
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.useEffect(() => {
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.useEffect(() => {
39
+ React.useLayoutEffect(() => {
39
40
  userControlledPositionRef.current = false;
40
41
  }, [node.getSelectedNode(), node.getRect().width, node.getRect().height]);
41
42
 
42
- React.useEffect(() => {
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 > 2 || getSize(selectedRect) > getSize(stripRect)) { // maybe 2 will prevent jitter?
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 > 2) {
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 = isTabOverflow ? 10 : 0; // prevents flashing, after sticky buttons docked set, must be 10 pixels smaller before unsetting
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 !== isTabOverflow) {
183
- setTabOverflow(dock);
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, isTabOverflow };
300
+ return { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs };
293
301
  };
294
302
 
295
303
  function arraysEqual(arr1: number[], arr2: number[]) {
@@ -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, isTabOverflow } =
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() && (isTabOverflow || isTabStretch)) {
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 (hiddenTabs.length > 0) {
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,
@@ -559,7 +559,7 @@
559
559
  --color-border-tab-unselected: gray;
560
560
  --color-border-tab-unselected-background: #d3d4e745;
561
561
 
562
- --color-splitter: #{$color_background};
562
+ --color-splitter: var(--color-background);
563
563
  --color-splitter-hover: var(--color-2);
564
564
  --color-splitter-drag: var(--color-2);
565
565