flexlayout-react 0.9.0 → 0.9.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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * flexlayout-react
3
- * @version 0.9.0
3
+ * @version 0.9.1
4
4
  */
5
5
  import * as React from "react";
6
6
  import { useEffect, useImperativeHandle, useRef } from "react";
@@ -279,7 +279,8 @@ var CLASSES = /* @__PURE__ */ function(CLASSES) {
279
279
  CLASSES["FLEXLAYOUT__FLOAT_WINDOW_CONTENT"] = "flexlayout__float_window_content";
280
280
  CLASSES["FLEXLAYOUT__FLOATING_WINDOW_CONTENT"] = "flexlayout__floating_window_content";
281
281
  CLASSES["FLEXLAYOUT__LAYOUT"] = "flexlayout__layout";
282
- CLASSES["FLEXLAYOUT__LAYOUT_MOVEABLES"] = "flexlayout__layout_moveables";
282
+ CLASSES["FLEXLAYOUT__LAYOUT_METRICS"] = "flexlayout__layout_metrics";
283
+ CLASSES["FLEXLAYOUT__LAYOUT_MOVEABLES_HOME"] = "flexlayout__layout_moveables_home";
283
284
  CLASSES["FLEXLAYOUT__LAYOUT_OVERLAY"] = "flexlayout__layout_overlay";
284
285
  CLASSES["FLEXLAYOUT__LAYOUT_TAB_STAMPS"] = "flexlayout__layout_tab_stamps";
285
286
  CLASSES["FLEXLAYOUT__LAYOUT_MAIN"] = "flexlayout__layout_main";
@@ -953,19 +954,20 @@ var TabNode = class TabNode extends Node {
953
954
  return new TabNode(model, json, addToModel);
954
955
  }
955
956
  tabRect = Rect.empty();
956
- moveableElement;
957
957
  renderedName;
958
958
  extra;
959
959
  visible;
960
960
  rendered;
961
+ moveableElement;
962
+ tabStamp;
961
963
  scrollTop;
962
964
  scrollLeft;
963
- tabStamp;
964
965
  /** @internal */
965
966
  constructor(model, json, addToModel = true) {
966
967
  super(model);
967
968
  this.extra = {};
968
- this.moveableElement = null;
969
+ this.moveableElement = document.createElement("div");
970
+ this.moveableElement.className = CLASSES.FLEXLAYOUT__TAB_MOVEABLE;
969
971
  this.tabStamp = null;
970
972
  this.rendered = false;
971
973
  this.visible = false;
@@ -1160,10 +1162,6 @@ var TabNode = class TabNode extends Node {
1160
1162
  return this.moveableElement;
1161
1163
  }
1162
1164
  /** @internal */
1163
- setMoveableElement(element) {
1164
- this.moveableElement = element;
1165
- }
1166
- /** @internal */
1167
1165
  setRenderedName(name) {
1168
1166
  this.renderedName = name;
1169
1167
  }
@@ -1227,7 +1225,7 @@ var TabNode = class TabNode extends Node {
1227
1225
  attributeDefinitions.addInherited("contentClassName", "tabContentClassName").setType(Attribute.STRING).setDescription(`class applied to tab content`);
1228
1226
  attributeDefinitions.addInherited("icon", "tabIcon").setType(Attribute.STRING).setDescription(`the tab icon`);
1229
1227
  attributeDefinitions.addInherited("enableRenderOnDemand", "tabEnableRenderOnDemand").setType(Attribute.BOOLEAN).setDescription(`whether to avoid rendering component until tab is visible`);
1230
- attributeDefinitions.addInherited("enablePopout", "tabEnablePopout").setType(Attribute.BOOLEAN).setAlias("enableFloat").setDescription(`enable popout (in popout capable browser)`);
1228
+ attributeDefinitions.addInherited("enablePopout", "tabEnablePopout").setType(Attribute.BOOLEAN).setAlias("enableFloat").setDescription(`enable window popout (in popout capable browser), to show an icon in the tabset header also set the enablePopoutIcon attribute`);
1231
1229
  attributeDefinitions.addInherited("enablePopoutIcon", "tabEnablePopoutIcon").setType(Attribute.BOOLEAN).setDescription(`whether to show the popout icon in the tabset header if this tab enables popouts`);
1232
1230
  attributeDefinitions.addInherited("enablePopoutFloatIcon", "tabEnablePopoutFloatIcon").setType(Attribute.BOOLEAN).setDescription(`whether to show the popout float icon in the tabset header if this tab enables floating popouts`);
1233
1231
  attributeDefinitions.addInherited("enablePopoutOverlay", "tabEnablePopoutOverlay").setType(Attribute.BOOLEAN).setDescription(`if this tab will not work correctly in a popout window when the main window is backgrounded (inactive)
@@ -1353,6 +1351,16 @@ function isSafari() {
1353
1351
  const userAgent = navigator.userAgent;
1354
1352
  return userAgent.includes("Safari") && !userAgent.includes("Chrome") && !userAgent.includes("Chromium");
1355
1353
  }
1354
+ function getPageMetrics() {
1355
+ return {
1356
+ scrollTop: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
1357
+ scrollLeft: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
1358
+ fullHeight: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight),
1359
+ fullWidth: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth, document.body.offsetWidth, document.documentElement.offsetWidth, document.body.clientWidth, document.documentElement.clientWidth),
1360
+ viewportHeight: window.innerHeight || document.documentElement.clientHeight,
1361
+ viewportWidth: window.innerWidth || document.documentElement.clientWidth
1362
+ };
1363
+ }
1356
1364
  //#endregion
1357
1365
  //#region src/model/RowNode.ts
1358
1366
  var RowNode = class RowNode extends Node {
@@ -2667,7 +2675,7 @@ var Model = class Model {
2667
2675
  * Update the node tree by performing the given action,
2668
2676
  * Actions should be generated via static methods on the Actions class
2669
2677
  * @param action the action to perform
2670
- * @returns added Node for Actions.addNode, layoutId for createPopout
2678
+ * @returns added Node for Actions.addTab, layoutId for createPopout
2671
2679
  */
2672
2680
  doAction(action) {
2673
2681
  let returnVal = void 0;
@@ -3332,7 +3340,7 @@ var I18nLabel = /* @__PURE__ */ function(I18nLabel) {
3332
3340
  I18nLabel["Close_Tabset"] = "Close tab set";
3333
3341
  I18nLabel["Active_Tabset"] = "Active tab set";
3334
3342
  I18nLabel["Move_Tabset"] = "Move tab set";
3335
- I18nLabel["Move_Tabs"] = "Move tabs(?)";
3343
+ I18nLabel["Move_Tabs"] = "Move tabs (?)";
3336
3344
  I18nLabel["Maximize"] = "Maximize tab set";
3337
3345
  I18nLabel["Restore"] = "Restore tab set";
3338
3346
  I18nLabel["Popout_Tab"] = "Popout selected tab";
@@ -3609,51 +3617,62 @@ var useTabOverflow = (controller, node, orientation, tabStripRef, miniScrollRef,
3609
3617
  const hiddenTabsRef = React.useRef([]);
3610
3618
  const thumbInternalPos = React.useRef(0);
3611
3619
  const repositioningRef = React.useRef(false);
3612
- hiddenTabsRef.current = hiddenTabs;
3613
3620
  React.useLayoutEffect(() => {
3614
- if (tabStripRef.current) setScrollPosition(0);
3615
- }, [node.getId()]);
3616
- React.useLayoutEffect(() => {
3617
- userControlledPositionRef.current = false;
3618
- }, [
3619
- node.getSelectedNode(),
3620
- node.getRect().width,
3621
- node.getRect().height
3622
- ]);
3623
- React.useLayoutEffect(() => {
3624
- checkForOverflow();
3625
- if (userControlledPositionRef.current === false) scrollIntoView();
3626
- updateScrollMetrics();
3627
- updateHiddenTabs();
3621
+ hiddenTabsRef.current = hiddenTabs;
3628
3622
  });
3629
- React.useEffect(() => {
3630
- selfRef.current?.addEventListener("wheel", onWheel, { passive: false });
3631
- return () => {
3632
- selfRef.current?.removeEventListener("wheel", onWheel);
3633
- };
3634
- }, [selfRef.current]);
3635
- const onWheel = (event) => {
3636
- event.preventDefault();
3637
- };
3638
- function scrollIntoView() {
3639
- const selectedTabNode = node.getSelectedNode();
3640
- if (selectedTabNode && tabStripRef.current) {
3641
- const stripRect = controller.getBoundingClientRect(tabStripRef.current);
3642
- const selectedRect = selectedTabNode.getTabRect();
3643
- let shift = getNear(stripRect) - getNear(selectedRect);
3644
- if (shift > 0 || getSize(selectedRect) > getSize(stripRect)) {
3645
- setScrollPosition(getScrollPosition(tabStripRef.current) - shift);
3646
- repositioningRef.current = true;
3647
- } else {
3648
- shift = getFar(selectedRect) - getFar(stripRect);
3649
- if (shift > 0) {
3650
- setScrollPosition(getScrollPosition(tabStripRef.current) + shift);
3651
- repositioningRef.current = true;
3623
+ const setScrollPosition = React.useCallback((p) => {
3624
+ if (orientation === Orientation.HORZ) tabStripRef.current.scrollLeft = p;
3625
+ else tabStripRef.current.scrollTop = p;
3626
+ }, [orientation, tabStripRef]);
3627
+ const getScrollPosition = React.useCallback((elm) => {
3628
+ if (orientation === Orientation.HORZ) return elm.scrollLeft;
3629
+ else return elm.scrollTop;
3630
+ }, [orientation]);
3631
+ const getElementSize = React.useCallback((elm) => {
3632
+ if (orientation === Orientation.HORZ) return elm.clientWidth;
3633
+ else return elm.clientHeight;
3634
+ }, [orientation]);
3635
+ const getScrollSize = React.useCallback((elm) => {
3636
+ if (orientation === Orientation.HORZ) return elm.scrollWidth;
3637
+ else return elm.scrollHeight;
3638
+ }, [orientation]);
3639
+ const getSize = React.useCallback((rect) => {
3640
+ if (orientation === Orientation.HORZ) return rect.width;
3641
+ else return rect.height;
3642
+ }, [orientation]);
3643
+ const getNear = React.useCallback((rect) => {
3644
+ if (orientation === Orientation.HORZ) return rect.x;
3645
+ else return rect.y;
3646
+ }, [orientation]);
3647
+ const getFar = React.useCallback((rect) => {
3648
+ if (orientation === Orientation.HORZ) return rect.right;
3649
+ else return rect.bottom;
3650
+ }, [orientation]);
3651
+ const findHiddenTabs = React.useCallback(() => {
3652
+ const hidden = [];
3653
+ if (tabStripRef.current) {
3654
+ const strip = tabStripRef.current;
3655
+ const stripRect = strip.getBoundingClientRect();
3656
+ const visibleNear = getNear(stripRect) - 1;
3657
+ const visibleFar = getFar(stripRect) + 1;
3658
+ const tabContainer = strip.firstElementChild;
3659
+ let i = 0;
3660
+ Array.from(tabContainer.children).forEach((child) => {
3661
+ const tabRect = child.getBoundingClientRect();
3662
+ if (child.classList.contains(tabClassName)) {
3663
+ if (getNear(tabRect) < visibleNear || getFar(tabRect) > visibleFar) hidden.push(i);
3664
+ i++;
3652
3665
  }
3653
- }
3666
+ });
3654
3667
  }
3655
- }
3656
- const updateScrollMetrics = () => {
3668
+ return hidden;
3669
+ }, [
3670
+ tabClassName,
3671
+ tabStripRef,
3672
+ getNear,
3673
+ getFar
3674
+ ]);
3675
+ const updateScrollMetrics = React.useCallback(() => {
3657
3676
  if (tabStripRef.current && miniScrollRef.current) {
3658
3677
  const t = tabStripRef.current;
3659
3678
  const s = miniScrollRef.current;
@@ -3680,31 +3699,71 @@ var useTabOverflow = (controller, node, orientation, tabStripRef, miniScrollRef,
3680
3699
  if (orientation === Orientation.HORZ) s.style.bottom = "0px";
3681
3700
  else s.style.right = "0px";
3682
3701
  }
3683
- };
3684
- const updateHiddenTabs = () => {
3685
- const showHidden = findHiddenTabs().length > 0;
3702
+ }, [
3703
+ orientation,
3704
+ tabStripRef,
3705
+ miniScrollRef,
3706
+ getElementSize,
3707
+ getScrollSize,
3708
+ getScrollPosition
3709
+ ]);
3710
+ const updateHiddenTabs = React.useCallback((isInitial = false) => {
3711
+ const newHiddenTabs = findHiddenTabs();
3712
+ const showHidden = newHiddenTabs.length > 0;
3686
3713
  if (showHidden !== isShowHiddenTabs) setShowHiddenTabs(showHidden);
3687
- if (updateHiddenTabsTimerRef.current === void 0) updateHiddenTabsTimerRef.current = setTimeout(() => {
3688
- const newHiddenTabs = findHiddenTabs();
3689
- if (!arraysEqual(newHiddenTabs, hiddenTabsRef.current)) setHiddenTabs(newHiddenTabs);
3714
+ if (isInitial) setHiddenTabs(newHiddenTabs);
3715
+ else if (updateHiddenTabsTimerRef.current === void 0) updateHiddenTabsTimerRef.current = setTimeout(() => {
3716
+ const currentHiddenTabs = findHiddenTabs();
3717
+ if (!arraysEqual(currentHiddenTabs, hiddenTabsRef.current)) setHiddenTabs(currentHiddenTabs);
3690
3718
  updateHiddenTabsTimerRef.current = void 0;
3691
3719
  }, 100);
3692
- };
3693
- const onScroll = () => {
3720
+ }, [findHiddenTabs, isShowHiddenTabs]);
3721
+ const scrollIntoView = React.useCallback(() => {
3722
+ const selectedTabNode = node.getSelectedNode();
3723
+ if (selectedTabNode && tabStripRef.current) {
3724
+ const stripRect = controller.getBoundingClientRect(tabStripRef.current);
3725
+ const selectedRect = selectedTabNode.getTabRect();
3726
+ let shift = getNear(stripRect) - getNear(selectedRect);
3727
+ if (shift > 0 || getSize(selectedRect) > getSize(stripRect)) {
3728
+ setScrollPosition(getScrollPosition(tabStripRef.current) - shift);
3729
+ repositioningRef.current = true;
3730
+ } else {
3731
+ shift = getFar(selectedRect) - getFar(stripRect);
3732
+ if (shift > 0) {
3733
+ setScrollPosition(getScrollPosition(tabStripRef.current) + shift);
3734
+ repositioningRef.current = true;
3735
+ }
3736
+ }
3737
+ }
3738
+ }, [
3739
+ node,
3740
+ controller,
3741
+ tabStripRef,
3742
+ getNear,
3743
+ getFar,
3744
+ getSize,
3745
+ getScrollPosition,
3746
+ setScrollPosition
3747
+ ]);
3748
+ const checkForOverflow = React.useCallback(() => {
3749
+ if (tabStripRef.current) {
3750
+ const tabContainer = tabStripRef.current.firstElementChild;
3751
+ const offset = isDockStickyButtons ? 10 : 0;
3752
+ const dock = getElementSize(tabContainer) + offset > getElementSize(tabStripRef.current);
3753
+ if (dock !== isDockStickyButtons) setDockStickyButtons(dock);
3754
+ }
3755
+ }, [
3756
+ tabStripRef,
3757
+ isDockStickyButtons,
3758
+ getElementSize
3759
+ ]);
3760
+ const onScroll = React.useCallback(() => {
3694
3761
  if (!repositioningRef.current) userControlledPositionRef.current = true;
3695
3762
  repositioningRef.current = false;
3696
3763
  updateScrollMetrics();
3697
3764
  updateHiddenTabs();
3698
- };
3699
- const onScrollPointerDown = (event) => {
3700
- event.stopPropagation();
3701
- miniScrollRef.current.setPointerCapture(event.pointerId);
3702
- const r = miniScrollRef.current.getBoundingClientRect();
3703
- if (orientation === Orientation.HORZ) thumbInternalPos.current = event.clientX - r.x;
3704
- else thumbInternalPos.current = event.clientY - r.y;
3705
- startDrag(event.currentTarget.ownerDocument, event, onDragMove, onDragEnd, onDragCancel);
3706
- };
3707
- const onDragMove = (x, y) => {
3765
+ }, [updateScrollMetrics, updateHiddenTabs]);
3766
+ const onDragMove = React.useCallback((x, y) => {
3708
3767
  if (tabStripRef.current && miniScrollRef.current) {
3709
3768
  const t = tabStripRef.current;
3710
3769
  const s = miniScrollRef.current;
@@ -3718,37 +3777,31 @@ var useTabOverflow = (controller, node, orientation, tabStripRef, miniScrollRef,
3718
3777
  thumb = Math.max(0, Math.min(scrollSize - thumbSize, thumb));
3719
3778
  if (size > 0) setScrollPosition(thumb * scrollSize / size);
3720
3779
  }
3721
- };
3722
- const onDragEnd = () => {};
3723
- const onDragCancel = () => {};
3724
- const checkForOverflow = () => {
3725
- if (tabStripRef.current) {
3726
- const tabContainer = tabStripRef.current.firstElementChild;
3727
- const offset = isDockStickyButtons ? 10 : 0;
3728
- const dock = getElementSize(tabContainer) + offset > getElementSize(tabStripRef.current);
3729
- if (dock !== isDockStickyButtons) setDockStickyButtons(dock);
3730
- }
3731
- };
3732
- const findHiddenTabs = () => {
3733
- const hidden = [];
3734
- if (tabStripRef.current) {
3735
- const strip = tabStripRef.current;
3736
- const stripRect = strip.getBoundingClientRect();
3737
- const visibleNear = getNear(stripRect) - 1;
3738
- const visibleFar = getFar(stripRect) + 1;
3739
- const tabContainer = strip.firstElementChild;
3740
- let i = 0;
3741
- Array.from(tabContainer.children).forEach((child) => {
3742
- const tabRect = child.getBoundingClientRect();
3743
- if (child.classList.contains(tabClassName)) {
3744
- if (getNear(tabRect) < visibleNear || getFar(tabRect) > visibleFar) hidden.push(i);
3745
- i++;
3746
- }
3747
- });
3748
- }
3749
- return hidden;
3750
- };
3751
- const onMouseWheel = (event) => {
3780
+ }, [
3781
+ tabStripRef,
3782
+ miniScrollRef,
3783
+ orientation,
3784
+ getElementSize,
3785
+ getScrollSize,
3786
+ setScrollPosition
3787
+ ]);
3788
+ const onDragEnd = React.useCallback(() => {}, []);
3789
+ const onDragCancel = React.useCallback(() => {}, []);
3790
+ const onScrollPointerDown = React.useCallback((event) => {
3791
+ event.stopPropagation();
3792
+ miniScrollRef.current.setPointerCapture(event.pointerId);
3793
+ const r = miniScrollRef.current.getBoundingClientRect();
3794
+ if (orientation === Orientation.HORZ) thumbInternalPos.current = event.clientX - r.x;
3795
+ else thumbInternalPos.current = event.clientY - r.y;
3796
+ startDrag(event.currentTarget.ownerDocument, event, onDragMove, onDragEnd, onDragCancel);
3797
+ }, [
3798
+ miniScrollRef,
3799
+ orientation,
3800
+ onDragMove,
3801
+ onDragEnd,
3802
+ onDragCancel
3803
+ ]);
3804
+ const onMouseWheel = React.useCallback((event) => {
3752
3805
  if (tabStripRef.current) {
3753
3806
  if (node.getChildren().length === 0) return;
3754
3807
  let delta;
@@ -3761,35 +3814,60 @@ var useTabOverflow = (controller, node, orientation, tabStripRef, miniScrollRef,
3761
3814
  event.stopPropagation();
3762
3815
  }
3763
3816
  }
3764
- };
3765
- const getNear = (rect) => {
3766
- if (orientation === Orientation.HORZ) return rect.x;
3767
- else return rect.y;
3768
- };
3769
- const getFar = (rect) => {
3770
- if (orientation === Orientation.HORZ) return rect.right;
3771
- else return rect.bottom;
3772
- };
3773
- const getElementSize = (elm) => {
3774
- if (orientation === Orientation.HORZ) return elm.clientWidth;
3775
- else return elm.clientHeight;
3776
- };
3777
- const getSize = (rect) => {
3778
- if (orientation === Orientation.HORZ) return rect.width;
3779
- else return rect.height;
3780
- };
3781
- const getScrollSize = (elm) => {
3782
- if (orientation === Orientation.HORZ) return elm.scrollWidth;
3783
- else return elm.scrollHeight;
3784
- };
3785
- const setScrollPosition = (p) => {
3786
- if (orientation === Orientation.HORZ) tabStripRef.current.scrollLeft = p;
3787
- else tabStripRef.current.scrollTop = p;
3788
- };
3789
- const getScrollPosition = (elm) => {
3790
- if (orientation === Orientation.HORZ) return elm.scrollLeft;
3791
- else return elm.scrollTop;
3792
- };
3817
+ }, [
3818
+ node,
3819
+ tabStripRef,
3820
+ getScrollPosition,
3821
+ getScrollSize,
3822
+ getElementSize,
3823
+ setScrollPosition
3824
+ ]);
3825
+ const onWheel = React.useCallback((event) => {
3826
+ event.preventDefault();
3827
+ }, []);
3828
+ const nodeId = node.getId();
3829
+ const selectedNode = node.getSelectedNode();
3830
+ const rectWidth = node.getRect().width;
3831
+ const rectHeight = node.getRect().height;
3832
+ React.useLayoutEffect(() => {
3833
+ if (tabStripRef.current) setScrollPosition(0);
3834
+ }, [
3835
+ nodeId,
3836
+ tabStripRef,
3837
+ setScrollPosition
3838
+ ]);
3839
+ React.useLayoutEffect(() => {
3840
+ userControlledPositionRef.current = false;
3841
+ }, [
3842
+ selectedNode,
3843
+ rectWidth,
3844
+ rectHeight
3845
+ ]);
3846
+ React.useLayoutEffect(() => {
3847
+ checkForOverflow();
3848
+ if (userControlledPositionRef.current === false) scrollIntoView();
3849
+ updateScrollMetrics();
3850
+ updateHiddenTabs(true);
3851
+ requestAnimationFrame(() => {
3852
+ updateHiddenTabs();
3853
+ });
3854
+ }, [
3855
+ checkForOverflow,
3856
+ scrollIntoView,
3857
+ updateScrollMetrics,
3858
+ updateHiddenTabs,
3859
+ rectWidth,
3860
+ rectHeight,
3861
+ orientation,
3862
+ selectedNode
3863
+ ]);
3864
+ React.useEffect(() => {
3865
+ const strip = selfRef.current;
3866
+ strip?.addEventListener("wheel", onWheel, { passive: false });
3867
+ return () => {
3868
+ strip?.removeEventListener("wheel", onWheel);
3869
+ };
3870
+ }, [onWheel]);
3793
3871
  return {
3794
3872
  selfRef,
3795
3873
  userControlledPositionRef,
@@ -3809,6 +3887,7 @@ function arraysEqual(arr1, arr2) {
3809
3887
  /** @internal */
3810
3888
  var TabSet = (props) => {
3811
3889
  const { tabsetNode, controller } = props;
3890
+ const selfRef = React.useRef(null);
3812
3891
  const tabStripRef = React.useRef(null);
3813
3892
  const miniScrollRef = React.useRef(null);
3814
3893
  const tabStripInnerRef = React.useRef(null);
@@ -3817,16 +3896,18 @@ var TabSet = (props) => {
3817
3896
  const overflowbuttonRef = React.useRef(null);
3818
3897
  const stickyButtonsRef = React.useRef(null);
3819
3898
  const icons = controller.getIcons();
3899
+ const { userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } = useTabOverflow(controller, tabsetNode, Orientation.HORZ, tabStripInnerRef, miniScrollRef, controller.getClassName(CLASSES.FLEXLAYOUT__TAB_BUTTON));
3820
3900
  React.useLayoutEffect(() => {
3821
- tabsetNode.setRect(controller.getBoundingClientRect(selfRef.current));
3901
+ if (selfRef.current) tabsetNode.setRect(controller.getBoundingClientRect(selfRef.current));
3822
3902
  if (tabStripRef.current) tabsetNode.setTabStripRect(controller.getBoundingClientRect(tabStripRef.current));
3823
- const newContentRect = controller.getBoundingClientRect(contentRef.current);
3824
- if (!tabsetNode.getContentRect().equalsWhenRounded(newContentRect) && !isNaN(newContentRect.x)) {
3825
- tabsetNode.setContentRect(newContentRect);
3826
- controller.setReLayout(true);
3903
+ if (contentRef.current) {
3904
+ const newContentRect = controller.getBoundingClientRect(contentRef.current);
3905
+ if (!tabsetNode.getContentRect().equalsWhenRounded(newContentRect) && !isNaN(newContentRect.x)) {
3906
+ tabsetNode.setContentRect(newContentRect);
3907
+ controller.setReLayout(true);
3908
+ }
3827
3909
  }
3828
3910
  });
3829
- const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } = useTabOverflow(controller, tabsetNode, Orientation.HORZ, tabStripInnerRef, miniScrollRef, controller.getClassName(CLASSES.FLEXLAYOUT__TAB_BUTTON));
3830
3911
  const onOverflowClick = (event) => {
3831
3912
  const callback = controller.getShowOverflowMenu();
3832
3913
  const items = hiddenTabs.map((h) => {
@@ -3995,7 +4076,7 @@ var TabSet = (props) => {
3995
4076
  children: typeof icons.popoutFloat === "function" ? icons.popoutFloat(selectedTabNode) : icons.popoutFloat
3996
4077
  }, "popout-float"));
3997
4078
  }
3998
- if (controller.isSupportsPopout() && selectedTabNode.isAllowedInWindow() && selectedTabNode.isEnablePopout()) {
4079
+ if (controller.isSupportsPopout() && selectedTabNode.isAllowedInWindow() && selectedTabNode.isEnablePopoutIcon()) {
3999
4080
  const popoutTitle = controller.i18nName(I18nLabel.Popout_Tab);
4000
4081
  buttons.push(/* @__PURE__ */ jsx("button", {
4001
4082
  "data-layout-path": path + "/button/popout",
@@ -4205,18 +4286,20 @@ var Splitter = (props) => {
4205
4286
  sum: 0,
4206
4287
  startPosition: 0
4207
4288
  });
4289
+ const onTouchStart = React.useCallback((event) => {
4290
+ event.preventDefault();
4291
+ event.stopImmediatePropagation();
4292
+ }, []);
4208
4293
  React.useEffect(() => {
4209
- selfRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4210
- extendedRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4294
+ const self = selfRef.current;
4295
+ const extended = extendedRef.current;
4296
+ self?.addEventListener("touchstart", onTouchStart, { passive: false });
4297
+ extended?.addEventListener("touchstart", onTouchStart, { passive: false });
4211
4298
  return () => {
4212
- selfRef.current?.removeEventListener("touchstart", onTouchStart);
4213
- extendedRef.current?.removeEventListener("touchstart", onTouchStart);
4299
+ self?.removeEventListener("touchstart", onTouchStart);
4300
+ extended?.removeEventListener("touchstart", onTouchStart);
4214
4301
  };
4215
- }, []);
4216
- const onTouchStart = (event) => {
4217
- event.preventDefault();
4218
- event.stopImmediatePropagation();
4219
- };
4302
+ }, [onTouchStart]);
4220
4303
  const onPointerDown = (event) => {
4221
4304
  event.stopPropagation();
4222
4305
  if (node instanceof RowNode) initalSizes.current = node.getSplitterInitials(index);
@@ -4356,27 +4439,36 @@ var Tab = (props) => {
4356
4439
  const { controller, selected, tabNode } = props;
4357
4440
  const selfRef = React.useRef(null);
4358
4441
  const firstSelect = React.useRef(true);
4442
+ const onPointerDown = React.useCallback(() => {
4443
+ const parent = tabNode.getParent();
4444
+ if (parent instanceof TabSetNode) {
4445
+ if (!parent.isActive()) controller.doAction(Actions.setActiveTabset(parent.getId(), controller.getLayoutId()));
4446
+ }
4447
+ }, [tabNode, controller]);
4359
4448
  const parentNode = tabNode.getParent();
4360
4449
  const rect = parentNode.getContentRect();
4361
4450
  React.useLayoutEffect(() => {
4451
+ const element = tabNode.getMoveableElement();
4452
+ selfRef.current.appendChild(element);
4362
4453
  const handleScroll = () => {
4363
4454
  tabNode.saveScrollPosition();
4364
4455
  };
4365
- const element = tabNode.getMoveableElement();
4366
- if (element) {
4367
- selfRef.current.appendChild(element);
4368
- element.addEventListener("scroll", handleScroll);
4369
- }
4370
- selfRef.current.addEventListener("pointerdown", onPointerDown);
4456
+ element.addEventListener("scroll", handleScroll);
4457
+ const self = selfRef.current;
4458
+ if (self) self.addEventListener("pointerdown", onPointerDown);
4371
4459
  return () => {
4372
- if (selfRef.current) selfRef.current.removeEventListener("pointerdown", onPointerDown);
4373
- if (element) {
4374
- if (!tabNode.isEnableWindowReMount()) controller.getMainController()?.getMoveablesDiv()?.appendChild(element);
4375
- element.removeEventListener("scroll", handleScroll);
4460
+ if (self) self.removeEventListener("pointerdown", onPointerDown);
4461
+ if (controller.getModel().getNodeById(tabNode.getId())) {
4462
+ if (!tabNode.isEnableWindowReMount()) controller.getMainController()?.getMoveablesHome()?.appendChild(element);
4376
4463
  }
4464
+ element.removeEventListener("scroll", handleScroll);
4377
4465
  tabNode.setVisible(false);
4378
4466
  };
4379
- }, [tabNode.getMoveableElement()]);
4467
+ }, [
4468
+ tabNode,
4469
+ controller,
4470
+ onPointerDown
4471
+ ]);
4380
4472
  React.useEffect(() => {
4381
4473
  if (tabNode.isSelected()) {
4382
4474
  if (firstSelect.current) {
@@ -4385,12 +4477,6 @@ var Tab = (props) => {
4385
4477
  }
4386
4478
  }
4387
4479
  });
4388
- const onPointerDown = () => {
4389
- const parent = tabNode.getParent();
4390
- if (parent instanceof TabSetNode) {
4391
- if (!parent.isActive()) controller.doAction(Actions.setActiveTabset(parent.getId(), controller.getLayoutId()));
4392
- }
4393
- };
4394
4480
  tabNode.setRect(rect);
4395
4481
  const cm = controller.getClassName;
4396
4482
  const style = {};
@@ -4521,6 +4607,7 @@ var DragDropManager = class DragDropManager {
4521
4607
  event.dataTransfer.effectAllowed = "copyMove";
4522
4608
  event.dataTransfer.dropEffect = "move";
4523
4609
  this._dragEnterCount = 0;
4610
+ this._controller.getModel().sortLayouts();
4524
4611
  if (node instanceof TabSetNode) {
4525
4612
  let rendered = false;
4526
4613
  let content = this._controller.i18nName(I18nLabel.Move_Tabset);
@@ -4569,7 +4656,6 @@ var DragDropManager = class DragDropManager {
4569
4656
  className: this._controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT) + " " + this._controller.getClassName(CLASSES.FLEXLAYOUT__DRAG_RECT),
4570
4657
  children: component
4571
4658
  });
4572
- this._controller.getModel().sortLayouts();
4573
4659
  const currentDocument = this._controller.getCurrentDocument();
4574
4660
  const tempDiv = currentDocument.createElement("div");
4575
4661
  tempDiv.setAttribute("data-layout-path", "/drag-rectangle");
@@ -4585,15 +4671,24 @@ var DragDropManager = class DragDropManager {
4585
4671
  }
4586
4672
  updateActive(event) {
4587
4673
  const layouts = Array.from(this._controller.getModel().getLayouts().values());
4588
- let foundActive = false;
4674
+ let found = void 0;
4675
+ let foundTab = void 0;
4589
4676
  for (let i = layouts.length - 1; i >= 0; i--) {
4590
- const manager = layouts[i].getController()?.getDragDropManager();
4591
- if (manager) {
4592
- const newActive = !foundActive && manager.getDragEnterCount() > 0;
4593
- if (newActive) foundActive = true;
4594
- manager.setActive(newActive, event);
4677
+ const layout = layouts[i];
4678
+ const dragDropManager = layout.getController()?.getDragDropManager();
4679
+ if (dragDropManager) {
4680
+ if (dragDropManager.getDragEnterCount() > 0) {
4681
+ if (layout.getType() === "tab") foundTab = layout;
4682
+ else if (!found && !foundTab) found = layout;
4683
+ }
4595
4684
  }
4596
4685
  }
4686
+ if (foundTab) {
4687
+ const parentLayout = findParentLayout(foundTab);
4688
+ if (found === parentLayout || !found) found = foundTab;
4689
+ }
4690
+ if (found) found.getController().getDragDropManager().setActive(true, event);
4691
+ for (const layout of layouts) if (layout !== found) layout.getController()?.getDragDropManager().setActive(false, event);
4597
4692
  }
4598
4693
  setActive(active, event) {
4599
4694
  if (this._active !== active) {
@@ -4640,7 +4735,8 @@ var DragDropManager = class DragDropManager {
4640
4735
  event.preventDefault();
4641
4736
  this._dropInfo = void 0;
4642
4737
  const rootdiv = this._controller.getRootDiv();
4643
- this._outlineDiv = this._controller.getCurrentDocument().createElement("div");
4738
+ const currentDocument = this._controller.getCurrentDocument();
4739
+ this._outlineDiv = currentDocument.createElement("div");
4644
4740
  this._outlineDiv.className = this._controller.getClassName(CLASSES.FLEXLAYOUT__OUTLINE_RECT);
4645
4741
  this._outlineDiv.style.visibility = "hidden";
4646
4742
  const speed = this._controller.getTabDragSpeed();
@@ -4695,7 +4791,7 @@ var DragDropManager = class DragDropManager {
4695
4791
  const dragState = DragDropManager.dragState;
4696
4792
  if (this._dropInfo) {
4697
4793
  if (dragState.dragJson !== void 0) {
4698
- const newNode = this._controller.doAction(Actions.addNode(dragState.dragJson, this._dropInfo.node.getId(), this._dropInfo.location, this._dropInfo.index));
4794
+ const newNode = this._controller.doAction(Actions.addTab(dragState.dragJson, this._dropInfo.node.getId(), this._dropInfo.location, this._dropInfo.index));
4699
4795
  if (dragState.fnNewNodeDropped !== void 0) dragState.fnNewNodeDropped(newNode, event);
4700
4796
  } else if (dragState.dragNode !== void 0) this._controller.doAction(Actions.moveNode(dragState.dragNode.getId(), this._dropInfo.node.getId(), this._dropInfo.location, this._dropInfo.index));
4701
4797
  }
@@ -4810,8 +4906,14 @@ var PopoutWindow = (props) => {
4810
4906
  const { title, controller, layout, url, onCloseLayout, onSetWindow: onSetLayout, children } = props;
4811
4907
  const popoutWindow = React.useRef(null);
4812
4908
  const [content, setContent] = React.useState(void 0);
4813
- const [firstRender, setFirstRender] = React.useState(true);
4814
- const styleMap = /* @__PURE__ */ new Map();
4909
+ const styleMap = React.useMemo(() => /* @__PURE__ */ new Map(), []);
4910
+ const initializedRef = React.useRef(false);
4911
+ React.useLayoutEffect(() => {
4912
+ if (!initializedRef.current && content) {
4913
+ initializedRef.current = true;
4914
+ controller.redrawLayout();
4915
+ }
4916
+ }, [content, controller]);
4815
4917
  React.useLayoutEffect(() => {
4816
4918
  if (!popoutWindow.current) {
4817
4919
  const layoutId = layout.getLayoutId();
@@ -4856,21 +4958,17 @@ var PopoutWindow = (props) => {
4856
4958
  }
4857
4959
  }
4858
4960
  return () => {
4859
- if (!controller.getModel().getLayouts().has(layout.getLayoutId())) {
4860
- popoutWindow.current?.close();
4861
- popoutWindow.current = null;
4862
- }
4961
+ popoutWindow.current?.close();
4962
+ popoutWindow.current = null;
4863
4963
  };
4864
- }, []);
4865
- React.useEffect(() => {
4866
- if (content !== void 0 && firstRender) {
4867
- controller.redrawLayout();
4868
- setFirstRender(false);
4869
- }
4870
4964
  }, [
4871
- content,
4872
- firstRender,
4873
- controller
4965
+ controller,
4966
+ layout,
4967
+ url,
4968
+ title,
4969
+ onCloseLayout,
4970
+ onSetLayout,
4971
+ styleMap
4874
4972
  ]);
4875
4973
  if (content !== void 0) return createPortal(children, content);
4876
4974
  else return null;
@@ -4942,32 +5040,56 @@ var FloatWindow = (props) => {
4942
5040
  const wRef = React.useRef(null);
4943
5041
  const nwRef = React.useRef(null);
4944
5042
  const moveToFrontRef = React.useRef(false);
5043
+ const clampToDoc = React.useCallback((rect) => {
5044
+ const layoutRect = Rect.fromDomRect(controller.getRootDiv().getBoundingClientRect());
5045
+ let boundaryRect;
5046
+ if (controller.getProps().constrainFloatPanels) boundaryRect = new Rect(0, 0, layoutRect.width, layoutRect.height);
5047
+ else {
5048
+ const page = getPageMetrics();
5049
+ const width = Math.max(page.fullWidth, window.innerWidth);
5050
+ const height = Math.max(page.fullHeight, window.innerHeight);
5051
+ boundaryRect = new Rect(-layoutRect.x, -layoutRect.y, width, height);
5052
+ }
5053
+ const clamped = rect.clone();
5054
+ clamped.clamp(boundaryRect);
5055
+ return clamped;
5056
+ }, [controller]);
5057
+ const onTouchStart = React.useCallback((event) => {
5058
+ event.preventDefault();
5059
+ event.stopImmediatePropagation();
5060
+ }, []);
4945
5061
  React.useEffect(() => {
4946
- headerRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4947
- nRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4948
- neRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4949
- eRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4950
- seRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4951
- sRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4952
- swRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4953
- wRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
4954
- nwRef.current?.addEventListener("touchstart", onTouchStart, { passive: false });
5062
+ const elements = [
5063
+ headerRef,
5064
+ nRef,
5065
+ neRef,
5066
+ eRef,
5067
+ seRef,
5068
+ sRef,
5069
+ swRef,
5070
+ wRef,
5071
+ nwRef
5072
+ ].map((r) => r.current).filter((el) => el !== null);
5073
+ elements.forEach((el) => el.addEventListener("touchstart", onTouchStart, { passive: false }));
4955
5074
  return () => {
4956
- headerRef.current?.removeEventListener("touchstart", onTouchStart);
4957
- nRef.current?.removeEventListener("touchstart", onTouchStart);
4958
- neRef.current?.removeEventListener("touchstart", onTouchStart);
4959
- eRef.current?.removeEventListener("touchstart", onTouchStart);
4960
- seRef.current?.removeEventListener("touchstart", onTouchStart);
4961
- sRef.current?.removeEventListener("touchstart", onTouchStart);
4962
- swRef.current?.removeEventListener("touchstart", onTouchStart);
4963
- wRef.current?.removeEventListener("touchstart", onTouchStart);
4964
- nwRef.current?.removeEventListener("touchstart", onTouchStart);
5075
+ elements.forEach((el) => el.removeEventListener("touchstart", onTouchStart));
4965
5076
  };
4966
- }, []);
4967
- const onTouchStart = (event) => {
4968
- event.preventDefault();
4969
- event.stopImmediatePropagation();
4970
- };
5077
+ }, [onTouchStart]);
5078
+ const initializedRef = React.useRef(false);
5079
+ React.useLayoutEffect(() => {
5080
+ if (!initializedRef.current) {
5081
+ initializedRef.current = true;
5082
+ const clamped = clampToDoc(rect);
5083
+ if (!clamped.equals(rect)) {
5084
+ setRect(clamped);
5085
+ layout.setRect(clamped);
5086
+ }
5087
+ }
5088
+ }, [
5089
+ clampToDoc,
5090
+ rect,
5091
+ layout
5092
+ ]);
4971
5093
  React.useEffect(() => {
4972
5094
  const onPointerDown = () => {
4973
5095
  const layouts = [...controller.getModel().getLayouts()];
@@ -4992,28 +5114,22 @@ var FloatWindow = (props) => {
4992
5114
  current.removeEventListener("pointerup", onPointerUp);
4993
5115
  }
4994
5116
  };
4995
- }, [controller, layout.getLayoutId()]);
5117
+ }, [controller, layout]);
4996
5118
  const onPointerDownHeader = (e) => {
4997
5119
  e.stopPropagation();
4998
5120
  const offset = {
4999
5121
  x: e.clientX - rect.x,
5000
5122
  y: e.clientY - rect.y
5001
5123
  };
5002
- const rootDiv = controller.getRootDiv();
5003
- const rootRect = rootDiv ? rootDiv.getBoundingClientRect() : {
5004
- width: window.innerWidth,
5005
- height: window.innerHeight
5006
- };
5007
5124
  startDrag(document, e, (x, y) => {
5008
5125
  controller.showOverlayOnAllWindows(true);
5009
5126
  if (moveToFrontRef.current) {
5010
5127
  controller.moveWindowToFront(layout.getLayoutId());
5011
5128
  moveToFrontRef.current = false;
5012
5129
  }
5013
- const newRect = new Rect(x - offset.x, y - offset.y, rect.width, rect.height);
5014
- newRect.clamp(new Rect(0, 0, rootRect.width, rootRect.height));
5015
- setRect(newRect);
5016
- layout.setRect(newRect);
5130
+ const clamped = clampToDoc(new Rect(x - offset.x, y - offset.y, rect.width, rect.height));
5131
+ setRect(clamped);
5132
+ layout.setRect(clamped);
5017
5133
  }, () => {
5018
5134
  controller.redrawLayout();
5019
5135
  controller.showOverlayOnAllWindows(false);
@@ -5025,11 +5141,6 @@ var FloatWindow = (props) => {
5025
5141
  x: e.clientX,
5026
5142
  y: e.clientY
5027
5143
  };
5028
- const rootDiv = controller.getRootDiv();
5029
- const rootRect = rootDiv ? rootDiv.getBoundingClientRect() : {
5030
- width: window.innerWidth,
5031
- height: window.innerHeight
5032
- };
5033
5144
  startDrag(document, e, (x, y) => {
5034
5145
  controller.showOverlayOnAllWindows(true);
5035
5146
  const dx = x - startPos.x;
@@ -5048,41 +5159,15 @@ var FloatWindow = (props) => {
5048
5159
  newW -= dx;
5049
5160
  }
5050
5161
  if (direction.includes("e")) newW += dx;
5051
- if (newW < MIN_WIDTH) {
5052
- if (direction.includes("w")) newX = startRect.x + startRect.width - MIN_WIDTH;
5053
- newW = MIN_WIDTH;
5054
- }
5055
- if (newH < MIN_HEIGHT) {
5056
- if (direction.includes("n")) newY = startRect.y + startRect.height - MIN_HEIGHT;
5057
- newH = MIN_HEIGHT;
5058
- }
5059
- if (newX < 0) {
5060
- newW += newX;
5061
- newX = 0;
5062
- }
5063
- if (newY < 0) {
5064
- newH += newY;
5065
- newY = 0;
5066
- }
5067
- if (newX + newW > rootRect.width) newW = rootRect.width - newX;
5068
- if (newY + newH > rootRect.height) newH = rootRect.height - newY;
5069
- if (newW < MIN_WIDTH) newW = MIN_WIDTH;
5070
- if (newH < MIN_HEIGHT) newH = MIN_HEIGHT;
5071
- const newRect = new Rect(newX, newY, newW, newH);
5072
- setRect(newRect);
5073
- layout.setRect(newRect);
5162
+ const clamped = clampToDoc(new Rect(newX, newY, Math.max(MIN_WIDTH, newW), Math.max(MIN_HEIGHT, newH)));
5163
+ setRect(clamped);
5164
+ layout.setRect(clamped);
5074
5165
  }, () => {
5075
5166
  controller.redrawLayout();
5076
5167
  controller.showOverlayOnAllWindows(false);
5077
5168
  }, () => {});
5078
5169
  e.stopPropagation();
5079
5170
  };
5080
- const rootDiv = controller.getRootDiv();
5081
- const rootRect = rootDiv ? rootDiv.getBoundingClientRect() : {
5082
- width: window.innerWidth,
5083
- height: window.innerHeight
5084
- };
5085
- rect.clamp(new Rect(0, 0, rootRect.width, rootRect.height));
5086
5171
  return /* @__PURE__ */ jsxs("div", {
5087
5172
  ref: selfRef,
5088
5173
  className: cm(CLASSES.FLEXLAYOUT__FLOAT_WINDOW),
@@ -5238,6 +5323,7 @@ var FloatingWindowContainer = ({ controller }) => {
5238
5323
  const floatingLayouts = [];
5239
5324
  const layouts = controller.getModel().getLayouts();
5240
5325
  let windowPopoutId = 0;
5326
+ let floatPopoutZIndex = 2e3;
5241
5327
  for (const [layoutId, layout] of layouts) if (!layout.isMainLayout()) {
5242
5328
  if (layout.getType() === "window" && controller.isSupportsPopout()) {
5243
5329
  floatingLayouts.push(/* @__PURE__ */ jsx(PopoutWindow, {
@@ -5257,16 +5343,20 @@ var FloatingWindowContainer = ({ controller }) => {
5257
5343
  })
5258
5344
  }, layoutId));
5259
5345
  windowPopoutId++;
5260
- } else if (layout.getType() === "float") floatingLayouts.push(/* @__PURE__ */ jsx(FloatWindow, {
5261
- controller,
5262
- layout,
5263
- onCloseLayout: controller.onCloseLayout,
5264
- children: /* @__PURE__ */ jsx(LayoutInternal, {
5265
- ...controller.getProps(),
5266
- layoutId,
5267
- mainLayoutController: controller
5268
- })
5269
- }, layoutId + "float"));
5346
+ } else if (layout.getType() === "float") {
5347
+ floatingLayouts.push(/* @__PURE__ */ jsx(FloatWindow, {
5348
+ controller,
5349
+ layout,
5350
+ zIndex: floatPopoutZIndex,
5351
+ onCloseLayout: controller.onCloseLayout,
5352
+ children: /* @__PURE__ */ jsx(LayoutInternal, {
5353
+ ...controller.getProps(),
5354
+ layoutId,
5355
+ mainLayoutController: controller
5356
+ })
5357
+ }, layoutId + "float"));
5358
+ floatPopoutZIndex++;
5359
+ }
5270
5360
  }
5271
5361
  return /* @__PURE__ */ jsx(Fragment, { children: floatingLayouts });
5272
5362
  };
@@ -5396,16 +5486,17 @@ var BorderButton = (props) => {
5396
5486
  /** @internal */
5397
5487
  var BorderTabSet = (props) => {
5398
5488
  const { borderNode, controller, size } = props;
5489
+ const selfRef = React.useRef(null);
5399
5490
  const toolbarRef = React.useRef(null);
5400
5491
  const miniScrollRef = React.useRef(null);
5401
5492
  const overflowbuttonRef = React.useRef(null);
5402
5493
  const stickyButtonsRef = React.useRef(null);
5403
5494
  const tabStripInnerRef = React.useRef(null);
5404
5495
  const icons = controller.getIcons();
5496
+ const { userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } = useTabOverflow(controller, borderNode, Orientation.flip(borderNode.getOrientation()), tabStripInnerRef, miniScrollRef, controller.getClassName(CLASSES.FLEXLAYOUT__BORDER_BUTTON));
5405
5497
  React.useLayoutEffect(() => {
5406
- borderNode.setTabHeaderRect(controller.getBoundingClientRect(selfRef.current));
5498
+ if (selfRef.current) borderNode.setTabHeaderRect(controller.getBoundingClientRect(selfRef.current));
5407
5499
  });
5408
- const { selfRef, userControlledPositionRef, onScroll, onScrollPointerDown, hiddenTabs, onMouseWheel, isDockStickyButtons, isShowHiddenTabs } = useTabOverflow(controller, borderNode, Orientation.flip(borderNode.getOrientation()), tabStripInnerRef, miniScrollRef, controller.getClassName(CLASSES.FLEXLAYOUT__BORDER_BUTTON));
5409
5500
  const onAuxMouseClick = (event) => {
5410
5501
  if (isAuxMouseEvent(event)) controller.auxMouseClick(borderNode, event);
5411
5502
  };
@@ -5787,15 +5878,15 @@ var BorderContainer = ({ controller, inner }) => {
5787
5878
  });
5788
5879
  };
5789
5880
  //#endregion
5790
- //#region src/view/DragContainer.tsx
5881
+ //#region src/view/DragTabButton.tsx
5791
5882
  /** @internal */
5792
- var DragContainer = React.memo((props) => {
5793
- DragContainer.displayName = "DragContainer";
5883
+ var DragTabButton = React.memo((props) => {
5884
+ DragTabButton.displayName = "DragTabButton";
5794
5885
  const { controller, tabNode } = props;
5795
5886
  const selfRef = React.useRef(null);
5796
5887
  React.useEffect(() => {
5797
5888
  tabNode.setTabStamp(selfRef.current);
5798
- }, [tabNode, selfRef.current]);
5889
+ }, [tabNode]);
5799
5890
  const cm = controller.getClassName;
5800
5891
  return /* @__PURE__ */ jsx("div", {
5801
5892
  ref: selfRef,
@@ -5820,10 +5911,10 @@ var LayoutInternal = React.forwardRef((props, ref) => {
5820
5911
  showEdges: false,
5821
5912
  showOverlay: false,
5822
5913
  calculatedBorderBarSize: 29,
5914
+ calculatedSplitterSize: 8,
5823
5915
  layoutRedrawRevision: 0,
5824
5916
  fullRedrawRevision: 0,
5825
- showHiddenBorder: DockLocation.CENTER,
5826
- splitterSize: 8
5917
+ showHiddenBorder: DockLocation.CENTER
5827
5918
  });
5828
5919
  const setState = React.useCallback((update) => {
5829
5920
  setStateRaw((prev) => ({
@@ -5832,16 +5923,18 @@ var LayoutInternal = React.forwardRef((props, ref) => {
5832
5923
  }));
5833
5924
  }, [props]);
5834
5925
  const layoutRef = React.useRef(null);
5835
- const moveablesRef = React.useRef(null);
5926
+ const moveablesHomeRef = React.useRef(null);
5836
5927
  const findBorderBarSizeRef = React.useRef(null);
5928
+ const findSplitterSizeRef = React.useRef(null);
5837
5929
  const mainRef = React.useRef(null);
5838
5930
  const controller = React.useMemo(() => new LayoutController(props, state, setState), []);
5839
5931
  controller.setProps(props);
5840
5932
  controller.setStateRaw(state);
5841
5933
  controller.setSetState(setState);
5842
5934
  controller.setLayoutRef(layoutRef);
5843
- controller.setMoveablesRef(moveablesRef);
5935
+ controller.setMoveablesHomeRef(moveablesHomeRef);
5844
5936
  controller.setFindBorderBarSizeRef(findBorderBarSizeRef);
5937
+ controller.setFindSplitterSizeRef(findSplitterSizeRef);
5845
5938
  controller.setMainRef(mainRef);
5846
5939
  React.useImperativeHandle(ref, () => controller, [controller]);
5847
5940
  React.useLayoutEffect(() => {
@@ -5904,61 +5997,57 @@ var LayoutInternal = React.forwardRef((props, ref) => {
5904
5997
  controller.setLayout(layout);
5905
5998
  if (controller.isMainLayout()) {
5906
5999
  currentModel.addChangeListener(controller.onModelChange);
5907
- const updateFromCSSVars = () => {
5908
- const size = parseInt(getComputedStyle(layoutRef.current).getPropertyValue("--splitter-size"));
5909
- if (Number.isFinite(size)) {
5910
- props.model.setSplitterSize(size);
5911
- if (state.splitterSize !== size) setState({ splitterSize: size });
5912
- }
5913
- };
5914
- updateFromCSSVars();
5915
- const cssVarUpdater = setInterval(updateFromCSSVars, 1e3);
5916
6000
  return () => {
5917
6001
  currentModel.removeChangeListener(controller.onModelChange);
5918
- clearInterval(cssVarUpdater);
5919
- controller.tidyMoveablesMap();
5920
6002
  };
5921
6003
  }
5922
6004
  }, [props.model, controller]);
5923
- if (!layoutRef.current) return /* @__PURE__ */ jsxs("div", {
5924
- ref: layoutRef,
5925
- className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT),
6005
+ const metrics = /* @__PURE__ */ jsxs("div", {
6006
+ className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_METRICS),
5926
6007
  children: [/* @__PURE__ */ jsx("div", {
5927
- ref: moveablesRef,
5928
- className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_MOVEABLES)
5929
- }, "__moveables__"), /* @__PURE__ */ jsx("div", {
5930
6008
  ref: findBorderBarSizeRef,
5931
6009
  className: controller.getClassName(CLASSES.FLEXLAYOUT__BORDER_SIZER),
5932
6010
  children: "FindBorderBarSize"
5933
- }, "findBorderBarSize")]
6011
+ }, "findBorderBarSize"), /* @__PURE__ */ jsx("div", {
6012
+ ref: findSplitterSizeRef,
6013
+ className: controller.getClassName(CLASSES.FLEXLAYOUT__SPLITTER_ + "horz")
6014
+ }, "findSplitterSize")]
6015
+ });
6016
+ if (!layoutRef.current) return /* @__PURE__ */ jsx("div", {
6017
+ ref: layoutRef,
6018
+ className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT),
6019
+ children: metrics
5934
6020
  });
5935
6021
  const model = props.model;
5936
6022
  const layoutId = controller.getLayoutId();
5937
6023
  model.getRootRow(layoutId).calcMinMaxSize();
5938
6024
  model.getRootRow(layoutId).setPaths("");
5939
- if (controller.isMainLayout()) {
5940
- model.getBorderSet().setPaths();
5941
- controller.createMoveableDivs();
5942
- }
6025
+ if (controller.isMainLayout()) model.getBorderSet().setPaths();
6026
+ const overlay = /* @__PURE__ */ jsx(Overlay, {
6027
+ controller,
6028
+ show: state.showOverlay
6029
+ }, "__overlay__");
5943
6030
  const outer = /* @__PURE__ */ jsx(BorderContainer, {
5944
6031
  controller,
5945
6032
  inner: controller.renderLayout()
5946
6033
  });
5947
6034
  const tabs = controller.renderTabContainers();
5948
6035
  const reorderedTabs = controller.reorderComponents(tabs, controller.getOrderedTabIds());
5949
- let metricElements = null;
5950
6036
  let floatingWindows = null;
5951
6037
  let reorderedTabContents = null;
5952
- let tabStamps = null;
6038
+ let dragTabButtons = null;
6039
+ let moveablesHome = null;
5953
6040
  if (controller.isMainLayout()) {
5954
- metricElements = controller.renderMetricsElements();
5955
6041
  floatingWindows = /* @__PURE__ */ jsx(FloatingWindowContainer, { controller });
5956
- const tabContents = controller.renderTabContents();
5957
- reorderedTabContents = controller.reorderComponents(tabContents, controller.getOrderedTabMoveableIds());
5958
- tabStamps = /* @__PURE__ */ jsx("div", {
6042
+ reorderedTabContents = controller.reorderComponents(controller.renderTabContents(), controller.getOrderedTabMoveableIds());
6043
+ dragTabButtons = /* @__PURE__ */ jsx("div", {
5959
6044
  className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_TAB_STAMPS),
5960
- children: controller.renderTabStamps()
5961
- }, "__tabStamps__");
6045
+ children: controller.renderDragTabButtons()
6046
+ }, "__dragTabButtons__");
6047
+ moveablesHome = /* @__PURE__ */ jsx("div", {
6048
+ ref: moveablesHomeRef,
6049
+ className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_MOVEABLES_HOME)
6050
+ }, "__moveables_home__");
5962
6051
  }
5963
6052
  return /* @__PURE__ */ jsxs("div", {
5964
6053
  ref: layoutRef,
@@ -5968,21 +6057,15 @@ var LayoutInternal = React.forwardRef((props, ref) => {
5968
6057
  onDragOver: controller.getDragDropManager().onDragOver,
5969
6058
  onDrop: controller.getDragDropManager().onDrop,
5970
6059
  children: [
5971
- /* @__PURE__ */ jsx("div", {
5972
- ref: moveablesRef,
5973
- className: controller.getClassName(CLASSES.FLEXLAYOUT__LAYOUT_MOVEABLES)
5974
- }, "__moveables__"),
5975
- metricElements,
5976
- /* @__PURE__ */ jsx(Overlay, {
5977
- controller,
5978
- show: state.showOverlay
5979
- }, "__overlay__"),
6060
+ metrics,
6061
+ moveablesHome,
6062
+ overlay,
5980
6063
  outer,
5981
6064
  reorderedTabs,
5982
6065
  reorderedTabContents,
5983
6066
  state.portal,
5984
6067
  floatingWindows,
5985
- tabStamps
6068
+ dragTabButtons
5986
6069
  ]
5987
6070
  });
5988
6071
  });
@@ -5993,12 +6076,12 @@ var LayoutController = class LayoutController {
5993
6076
  _state;
5994
6077
  _setState;
5995
6078
  _layoutRef;
5996
- _moveablesRef;
6079
+ _moveablesHomeRef;
5997
6080
  _findBorderBarSizeRef;
6081
+ _findSplitterSizeRef;
5998
6082
  _mainRef;
5999
6083
  _orderedTabIds;
6000
6084
  _orderedTabMoveableIds;
6001
- _moveableElementMap = /* @__PURE__ */ new Map();
6002
6085
  _currentDocument;
6003
6086
  _currentWindow;
6004
6087
  _supportsPopout;
@@ -6084,58 +6167,19 @@ var LayoutController = class LayoutController {
6084
6167
  });
6085
6168
  return tabContents;
6086
6169
  }
6087
- renderMetricsElements() {
6088
- return /* @__PURE__ */ jsx("div", {
6089
- ref: this._findBorderBarSizeRef,
6090
- className: this.getClassName(CLASSES.FLEXLAYOUT__BORDER_SIZER),
6091
- children: "FindBorderBarSize"
6092
- }, "findBorderBarSize");
6093
- }
6094
- renderTabStamps() {
6095
- const tabStamps = [];
6170
+ renderDragTabButtons() {
6171
+ const dragTabButtons = [];
6096
6172
  this._props.model.visitNodes((node) => {
6097
6173
  if (node instanceof TabNode) {
6098
6174
  const child = node;
6099
- tabStamps.push(/* @__PURE__ */ jsx(DragContainer, {
6175
+ dragTabButtons.push(/* @__PURE__ */ jsx(DragTabButton, {
6100
6176
  controller: this,
6101
6177
  tabNode: child,
6102
6178
  dragging: Utils_dragging
6103
6179
  }, child.getId()));
6104
6180
  }
6105
6181
  });
6106
- return tabStamps;
6107
- }
6108
- createMoveableDivs() {
6109
- this._props.model.visitNodes((node) => {
6110
- if (node instanceof TabNode) {
6111
- const tabNode = node;
6112
- const element = this.getMoveableElement(tabNode.getId());
6113
- tabNode.setMoveableElement(element);
6114
- }
6115
- });
6116
- }
6117
- getMoveablesDiv() {
6118
- return this._moveablesRef.current;
6119
- }
6120
- getMoveableElement(id) {
6121
- let moveableElement = this._moveableElementMap.get(id);
6122
- if (moveableElement === void 0) {
6123
- moveableElement = document.createElement("div");
6124
- this._moveablesRef.current.appendChild(moveableElement);
6125
- moveableElement.className = CLASSES.FLEXLAYOUT__TAB_MOVEABLE;
6126
- this._moveableElementMap.set(id, moveableElement);
6127
- }
6128
- return moveableElement;
6129
- }
6130
- tidyMoveablesMap() {
6131
- const tabs = /* @__PURE__ */ new Map();
6132
- this._props.model.visitNodes((node, _) => {
6133
- if (node instanceof TabNode) tabs.set(node.getId(), node);
6134
- });
6135
- for (const [nodeId, element] of this._moveableElementMap) if (!tabs.has(nodeId)) {
6136
- element.remove();
6137
- this._moveableElementMap.delete(nodeId);
6138
- }
6182
+ return dragTabButtons;
6139
6183
  }
6140
6184
  redrawLayout() {
6141
6185
  this._mainController?.setState((state) => {
@@ -6208,7 +6252,14 @@ var LayoutController = class LayoutController {
6208
6252
  updateLayoutMetrics = () => {
6209
6253
  if (this._findBorderBarSizeRef.current) {
6210
6254
  const borderBarSize = this._findBorderBarSizeRef.current.getBoundingClientRect().height;
6211
- if (borderBarSize !== this._state.calculatedBorderBarSize) this.setState({ calculatedBorderBarSize: borderBarSize });
6255
+ if (Math.abs(borderBarSize - this._state.calculatedBorderBarSize) > .5) this.setState({ calculatedBorderBarSize: borderBarSize });
6256
+ }
6257
+ if (this._findSplitterSizeRef.current) {
6258
+ const splitterBarSize = this._findSplitterSizeRef.current.getBoundingClientRect().width;
6259
+ if (Math.abs(splitterBarSize - this._state.calculatedSplitterSize) > .5) {
6260
+ this._props.model.setSplitterSize(splitterBarSize);
6261
+ this.setState({ calculatedSplitterSize: splitterBarSize });
6262
+ }
6212
6263
  }
6213
6264
  };
6214
6265
  addTabWithDragAndDrop(event, json, onDrop) {
@@ -6220,6 +6271,9 @@ var LayoutController = class LayoutController {
6220
6271
  setDragComponent(event, component, x, y) {
6221
6272
  this._dragDropManager.setDragComponent(event, component, x, y);
6222
6273
  }
6274
+ getMoveablesHome() {
6275
+ return this._moveablesHomeRef.current;
6276
+ }
6223
6277
  getProps() {
6224
6278
  return this._props;
6225
6279
  }
@@ -6244,11 +6298,8 @@ var LayoutController = class LayoutController {
6244
6298
  setLayoutRef(value) {
6245
6299
  this._layoutRef = value;
6246
6300
  }
6247
- getMoveablesRef() {
6248
- return this._moveablesRef;
6249
- }
6250
- setMoveablesRef(value) {
6251
- this._moveablesRef = value;
6301
+ setMoveablesHomeRef(value) {
6302
+ this._moveablesHomeRef = value;
6252
6303
  }
6253
6304
  getFindBorderBarSizeRef() {
6254
6305
  return this._findBorderBarSizeRef;
@@ -6256,6 +6307,12 @@ var LayoutController = class LayoutController {
6256
6307
  setFindBorderBarSizeRef(value) {
6257
6308
  this._findBorderBarSizeRef = value;
6258
6309
  }
6310
+ getFindSplitterSizeRef() {
6311
+ return this._findBorderBarSizeRef;
6312
+ }
6313
+ setFindSplitterSizeRef(value) {
6314
+ this._findSplitterSizeRef = value;
6315
+ }
6259
6316
  getMainRef() {
6260
6317
  return this._mainRef;
6261
6318
  }
@@ -6325,9 +6382,6 @@ var LayoutController = class LayoutController {
6325
6382
  if (layoutRect) return Rect.getBoundingClientRect(div).relativeTo(layoutRect);
6326
6383
  return Rect.empty();
6327
6384
  }
6328
- getMoveableContainer() {
6329
- return this._moveablesRef.current;
6330
- }
6331
6385
  getClassName = (defaultClassName) => {
6332
6386
  if (this._props.classNameMapper === void 0) return defaultClassName;
6333
6387
  else return this._props.classNameMapper(defaultClassName);
@@ -6391,11 +6445,11 @@ var LayoutController = class LayoutController {
6391
6445
  this.doAction(Actions.movePopoutToFront(layoutId));
6392
6446
  }
6393
6447
  addTabToTabSet(tabsetId, json) {
6394
- if (this._props.model.getNodeById(tabsetId) !== void 0) return this.doAction(Actions.addNode(json, tabsetId, DockLocation.CENTER, -1));
6448
+ if (this._props.model.getNodeById(tabsetId) !== void 0) return this.doAction(Actions.addTab(json, tabsetId, DockLocation.CENTER, -1));
6395
6449
  }
6396
6450
  addTabToActiveTabSet(json) {
6397
6451
  const tabsetNode = this._props.model.getActiveTabset(this._layoutId);
6398
- if (tabsetNode !== void 0) return this.doAction(Actions.addNode(json, tabsetNode.getId(), DockLocation.CENTER, -1));
6452
+ if (tabsetNode !== void 0) return this.doAction(Actions.addTab(json, tabsetNode.getId(), DockLocation.CENTER, -1));
6399
6453
  }
6400
6454
  showControlInPortal = (control, element) => {
6401
6455
  const portal = createPortal(control, element);
@@ -6462,6 +6516,12 @@ var defaultSupportsPopout = isDesktop();
6462
6516
  var Layout = React.forwardRef((props, ref) => {
6463
6517
  const controllerRef = useRef(null);
6464
6518
  const renderRevision = useRef(0);
6519
+ const lastModel = useRef(props.model);
6520
+ const key = useRef(0);
6521
+ if (lastModel.current !== props.model) {
6522
+ key.current++;
6523
+ lastModel.current = props.model;
6524
+ }
6465
6525
  Layout.displayName = "Layout";
6466
6526
  useImperativeHandle(ref, () => ({
6467
6527
  redraw: () => {
@@ -6490,9 +6550,9 @@ var Layout = React.forwardRef((props, ref) => {
6490
6550
  ref: controllerRef,
6491
6551
  ...props,
6492
6552
  parentRedrawRevision: renderRevision.current++
6493
- });
6553
+ }, key.current);
6494
6554
  });
6495
- var FlexLayoutVersion = "0.9.0";
6555
+ var FlexLayoutVersion = "0.9.1";
6496
6556
  //#endregion
6497
6557
  //#region src/view/TabLayout.tsx
6498
6558
  /**