@aptre/flex-layout 0.4.3 → 0.4.4

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.
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom/vitest";
package/dist/index.mjs CHANGED
@@ -4938,6 +4938,12 @@ var Tab = (props) => {
4938
4938
  }
4939
4939
  }
4940
4940
  }, [selected]);
4941
+ React17.useLayoutEffect(() => {
4942
+ node.setRect(rect);
4943
+ }, [rect, node]);
4944
+ React17.useLayoutEffect(() => {
4945
+ node.setVisible(selected);
4946
+ }, [selected, node]);
4941
4947
  const onPointerDown = () => {
4942
4948
  const parent = node.getParent();
4943
4949
  if (parent instanceof TabSetNode) {
@@ -4946,13 +4952,11 @@ var Tab = (props) => {
4946
4952
  }
4947
4953
  }
4948
4954
  };
4949
- node.setRect(rect);
4950
4955
  const cm = layout.getClassName;
4951
4956
  const style2 = {};
4952
4957
  rect.styleWithPosition(style2);
4953
4958
  let overlay = null;
4954
4959
  if (selected) {
4955
- node.setVisible(true);
4956
4960
  if (document.hidden && node.isEnablePopoutOverlay()) {
4957
4961
  const overlayStyle = {};
4958
4962
  rect.styleWithPosition(overlayStyle);
@@ -4960,7 +4964,6 @@ var Tab = (props) => {
4960
4964
  }
4961
4965
  } else {
4962
4966
  style2.display = "none";
4963
- node.setVisible(false);
4964
4967
  }
4965
4968
  if (parentNode instanceof TabSetNode) {
4966
4969
  if (node.getModel().getMaximizedTabset(layout.getWindowId()) !== void 0) {
@@ -5897,9 +5900,24 @@ var DragState = class {
5897
5900
 
5898
5901
  // src/view/OptimizedLayout.tsx
5899
5902
  import * as React20 from "react";
5900
- import { useCallback, useEffect as useEffect6, useMemo, useRef as useRef12, useState as useState4 } from "react";
5901
- function TabRef({ node, onRectChange, onVisibilityChange }) {
5903
+ import { useCallback, useEffect as useEffect6, useState as useState4 } from "react";
5904
+ function createTabInfo(node) {
5905
+ const parent = node.getParent();
5906
+ const contentRect = parent?.getContentRect() ?? Rect.empty();
5907
+ return {
5908
+ node,
5909
+ rect: contentRect,
5910
+ visible: node.isSelected()
5911
+ };
5912
+ }
5913
+ function TabRef({
5914
+ node,
5915
+ onTabMount,
5916
+ onRectChange,
5917
+ onVisibilityChange
5918
+ }) {
5902
5919
  useEffect6(() => {
5920
+ onTabMount(node);
5903
5921
  const handleResize = (params) => {
5904
5922
  onRectChange(node.getId(), params.rect);
5905
5923
  };
@@ -5920,7 +5938,7 @@ function TabRef({ node, onRectChange, onVisibilityChange }) {
5920
5938
  node.removeEventListener("resize");
5921
5939
  node.removeEventListener("visibility");
5922
5940
  };
5923
- }, [node, onRectChange, onVisibilityChange]);
5941
+ }, [node, onTabMount, onRectChange, onVisibilityChange]);
5924
5942
  return null;
5925
5943
  }
5926
5944
  function TabContainer({
@@ -5980,37 +5998,43 @@ function TabContainer({
5980
5998
  })
5981
5999
  );
5982
6000
  }
5983
- function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange, ...layoutProps }) {
6001
+ function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange, onModelChange: userOnModelChange, ...layoutProps }) {
5984
6002
  const [isDragging, setIsDragging] = useState4(false);
5985
6003
  const [tabs, setTabs] = useState4(() => /* @__PURE__ */ new Map());
5986
- const tabNodesRef = useRef12(/* @__PURE__ */ new Map());
5987
- useEffect6(() => {
5988
- const newTabNodes = /* @__PURE__ */ new Map();
5989
- model.visitNodes((node) => {
5990
- if (node instanceof TabNode) {
5991
- newTabNodes.set(node.getId(), node);
5992
- }
5993
- });
5994
- tabNodesRef.current = newTabNodes;
5995
- setTabs((prevTabs) => {
6004
+ const syncTabsWithModel = useCallback(
6005
+ (prevTabs) => {
6006
+ const modelTabNodes = /* @__PURE__ */ new Map();
6007
+ model.visitNodes((node) => {
6008
+ if (node instanceof TabNode) {
6009
+ modelTabNodes.set(node.getId(), node);
6010
+ }
6011
+ });
5996
6012
  const nextTabs = /* @__PURE__ */ new Map();
5997
- for (const [nodeId, node] of newTabNodes) {
6013
+ let changed = false;
6014
+ for (const [nodeId, node] of modelTabNodes) {
5998
6015
  const existing = prevTabs.get(nodeId);
5999
6016
  if (existing) {
6000
6017
  nextTabs.set(nodeId, { ...existing, node });
6001
6018
  } else {
6002
- const parent = node.getParent();
6003
- const contentRect = parent?.getContentRect() ?? Rect.empty();
6004
- nextTabs.set(nodeId, {
6005
- node,
6006
- rect: contentRect,
6007
- visible: node.isSelected()
6008
- });
6019
+ nextTabs.set(nodeId, createTabInfo(node));
6020
+ changed = true;
6021
+ }
6022
+ }
6023
+ for (const nodeId of prevTabs.keys()) {
6024
+ if (!modelTabNodes.has(nodeId)) {
6025
+ changed = true;
6009
6026
  }
6010
6027
  }
6028
+ if (!changed && nextTabs.size === prevTabs.size) {
6029
+ return prevTabs;
6030
+ }
6011
6031
  return nextTabs;
6012
- });
6013
- }, [model]);
6032
+ },
6033
+ [model]
6034
+ );
6035
+ useEffect6(() => {
6036
+ setTabs((prevTabs) => syncTabsWithModel(prevTabs));
6037
+ }, [syncTabsWithModel]);
6014
6038
  const handleRectChange = useCallback((nodeId, rect) => {
6015
6039
  setTabs((prevTabs) => {
6016
6040
  const existing = prevTabs.get(nodeId);
@@ -6033,6 +6057,16 @@ function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange,
6033
6057
  return nextTabs;
6034
6058
  });
6035
6059
  }, []);
6060
+ const handleTabMount = useCallback((node) => {
6061
+ setTabs((prevTabs) => {
6062
+ if (prevTabs.has(node.getId())) {
6063
+ return prevTabs;
6064
+ }
6065
+ const nextTabs = new Map(prevTabs);
6066
+ nextTabs.set(node.getId(), createTabInfo(node));
6067
+ return nextTabs;
6068
+ });
6069
+ }, []);
6036
6070
  const handleDragStateChange = useCallback(
6037
6071
  (dragging) => {
6038
6072
  setIsDragging(dragging);
@@ -6040,14 +6074,20 @@ function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange,
6040
6074
  },
6041
6075
  [onDragStateChange]
6042
6076
  );
6077
+ const handleModelChange = useCallback(
6078
+ (changedModel, action) => {
6079
+ setTabs((prevTabs) => syncTabsWithModel(prevTabs));
6080
+ userOnModelChange?.(changedModel, action);
6081
+ },
6082
+ [syncTabsWithModel, userOnModelChange]
6083
+ );
6043
6084
  const factory = useCallback(
6044
6085
  (node) => {
6045
- return /* @__PURE__ */ React20.createElement(TabRef, { key: node.getId(), node, onRectChange: handleRectChange, onVisibilityChange: handleVisibilityChange });
6086
+ return /* @__PURE__ */ React20.createElement(TabRef, { key: node.getId(), node, onTabMount: handleTabMount, onRectChange: handleRectChange, onVisibilityChange: handleVisibilityChange });
6046
6087
  },
6047
- [handleRectChange, handleVisibilityChange]
6088
+ [handleTabMount, handleRectChange, handleVisibilityChange]
6048
6089
  );
6049
- const tabsForContainer = useMemo(() => tabs, [tabs]);
6050
- return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Layout, { model, factory, classNameMapper, onDragStateChange: handleDragStateChange, ...layoutProps }), /* @__PURE__ */ React20.createElement(TabContainer, { tabs: tabsForContainer, renderTab, isDragging, classNameMapper }));
6090
+ return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Layout, { model, factory, classNameMapper, onDragStateChange: handleDragStateChange, onModelChange: handleModelChange, ...layoutProps }), /* @__PURE__ */ React20.createElement(TabContainer, { tabs, renderTab, isDragging, classNameMapper }));
6051
6091
  }
6052
6092
 
6053
6093
  // src/model/walk.ts
@@ -26,4 +26,4 @@ export interface IOptimizedLayoutProps extends Omit<ILayoutProps, "factory"> {
26
26
  *
27
27
  * @see https://github.com/caplin/FlexLayout/issues/456
28
28
  */
29
- export declare function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange, ...layoutProps }: IOptimizedLayoutProps): React.JSX.Element;
29
+ export declare function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange, onModelChange: userOnModelChange, ...layoutProps }: IOptimizedLayoutProps): React.JSX.Element;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@aptre/flex-layout",
3
3
  "author": "Caplin Systems Ltd",
4
4
  "description": "A multi-tab docking layout manager",
5
- "version": "0.4.3",
5
+ "version": "0.4.4",
6
6
  "license": "ISC",
7
7
  "repository": {
8
8
  "type": "git",
@@ -68,8 +68,8 @@
68
68
  "build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/",
69
69
  "format": "prettier --write './style/*.scss' './{src,declarations}/**/(*.ts|*.tsx|*.html)' '*.json' '.vscode/*.json' '.github/**/*.json' '.prettierrc.yml' '.github/**/*.yml'",
70
70
  "typecheck": "tsgo --noEmit -p tsconfig.json",
71
- "test": "npm run typecheck && npm run test:js && npm run test:browser",
72
- "test:js": "vitest --config=vitest.config.ts --run",
71
+ "test": "npm run typecheck && npm run test:browser",
72
+ "test:js": "vitest --config=vitest.config.ts --run --passWithNoTests",
73
73
  "test:browser": "vitest --config=vitest.browser.config.ts --run",
74
74
  "test:browser:watch": "vitest --config=vitest.browser.config.ts",
75
75
  "test:browser:ui": "cross-env BROWSER_TEST_UI=1 vitest --config=vitest.browser.config.ts",
@@ -107,6 +107,7 @@
107
107
  "eslint-plugin-react": "^7.37.2",
108
108
  "globals": "^16.0.0",
109
109
  "happy-dom": "^20.0.11",
110
+ "jsdom": "^27.3.0",
110
111
  "playwright": "^1.57.0",
111
112
  "prettier": "^3.0.0",
112
113
  "prismjs": "^1.28.0",
@@ -1 +0,0 @@
1
- export {};