From f7d077a1d71d51139ce7386be0538dcdd29c08e1 Mon Sep 17 00:00:00 2001 From: John Walley Date: Sun, 10 Apr 2022 17:03:05 +0100 Subject: [PATCH] feat: avoid unmounting pane with same key which changes position (#226) --- package.json | 2 ++ src/allotment.tsx | 30 ++++++++++++++++++++++++++++++ src/split-view/split-view.ts | 32 ++++++++++++++++++++++++++++++++ yarn.lock | 12 ++++++++++++ 4 files changed, 76 insertions(+) diff --git a/package.json b/package.json index f8c2037d..8232363c 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "eventemitter3": "^4.0.0", "lodash.clamp": "^4.0.0", "lodash.debounce": "^4.0.0", + "lodash.isequal": "^4.5.0", "use-resize-observer": "^8.0.0" }, "devDependencies": { @@ -50,6 +51,7 @@ "@types/jest": "27.4.1", "@types/lodash.clamp": "4.0.6", "@types/lodash.debounce": "4.0.6", + "@types/lodash.isequal": "4.5.5", "@typescript-eslint/parser": "5.18.0", "@vscode/codicons": "0.0.29", "babel-jest": "27.5.1", diff --git a/src/allotment.tsx b/src/allotment.tsx index 837a3f31..58526347 100644 --- a/src/allotment.tsx +++ b/src/allotment.tsx @@ -1,5 +1,6 @@ import classNames from "classnames"; import clamp from "lodash.clamp"; +import isEqual from "lodash.isequal"; import React, { forwardRef, useCallback, @@ -260,6 +261,7 @@ const Allotment = forwardRef( useEffect(() => { if (dimensionsInitialized) { const keys = childrenArray.map((child) => child.key as string); + const panes = [...previousKeys.current]; const enter = keys.filter((key) => !previousKeys.current.includes(key)); const update = keys.filter((key) => previousKeys.current.includes(key)); @@ -268,6 +270,7 @@ const Allotment = forwardRef( exit.forEach((flag, index) => { if (flag) { splitViewRef.current?.removeView(index); + panes.splice(index, 1); views.current.splice(index, 1); } }); @@ -292,6 +295,12 @@ const Allotment = forwardRef( keys.findIndex((key) => key === enterKey) ); + panes.splice( + keys.findIndex((key) => key === enterKey), + 0, + enterKey + ); + views.current.splice( keys.findIndex((key) => key === enterKey), 0, @@ -299,6 +308,27 @@ const Allotment = forwardRef( ); } + // Move panes if order has changed + while (!isEqual(keys, panes)) { + for (const [i, key] of keys.entries()) { + const index = panes.findIndex((pane) => pane === key); + + if (index !== i) { + splitViewRef.current?.moveView( + splitViewViewRef.current.get(key) as HTMLElement, + index, + i + ); + + const tempKey = panes[index]; + panes.splice(index, 1); + panes.splice(i, 0, tempKey); + + break; + } + } + } + for (const enterKey of enter) { const index = keys.findIndex((key) => key === enterKey); diff --git a/src/split-view/split-view.ts b/src/split-view/split-view.ts index 2d75f973..2ddbdc25 100644 --- a/src/split-view/split-view.ts +++ b/src/split-view/split-view.ts @@ -565,6 +565,38 @@ export class SplitView extends EventEmitter implements Disposable { return view; } + /** + * Move a {@link View view} to a different index. + * + * @param from The source index. + * @param to The target index. + */ + public moveView(container: HTMLElement, from: number, to: number): void { + const cachedVisibleSize = this.getViewCachedVisibleSize(from); + + const sizing = + typeof cachedVisibleSize === "undefined" + ? this.getViewSize(from) + : Sizing.Invisible(cachedVisibleSize); + + const view = this.removeView(from); + this.addView(container, view, sizing, to); + } + + /** + * Returns the {@link View view}'s size previously to being hidden. + * + * @param index The {@link View view} index. + */ + private getViewCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.viewItems.length) { + throw new Error("Index out of bounds"); + } + + const viewItem = this.viewItems[index]; + return viewItem.cachedVisibleSize; + } + /** * Layout the {@link SplitView}. * diff --git a/yarn.lock b/yarn.lock index 9cc179a1..f70776d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3779,6 +3779,13 @@ dependencies: "@types/lodash" "*" +"@types/lodash.isequal@4.5.5": + version "4.5.5" + resolved "https://registry.yarnpkg.com/@types/lodash.isequal/-/lodash.isequal-4.5.5.tgz#4fed1b1b00bef79e305de0352d797e9bb816c8ff" + integrity sha512-4IKbinG7MGP131wRfceK6W4E/Qt3qssEFLF30LnJbjYiSfHGGRU/Io8YxXrZX109ir+iDETC8hw8QsDijukUVg== + dependencies: + "@types/lodash" "*" + "@types/lodash@*": version "4.14.175" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" @@ -9479,6 +9486,11 @@ lodash.debounce@^4.0.0, lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"