Jelajahi Sumber

feat: Panel support keepDOM (#1007)

* feat: Panel support keepDOM

* chore: cleanup code
squall 1 bulan lalu
induk
melakukan
498454d864

+ 9 - 2
packages/plugins/panel-manager-plugin/src/components/panel-layer/panel.tsx

@@ -19,9 +19,10 @@ const PanelItem: React.FC<{ panel: PanelEntity }> = ({ panel }) => {
 
   const isHorizontal = ['right', 'docked-right'].includes(panel.area);
 
-  const { size, fullscreen } = usePanelStore((s) => ({ size: s.size, fullscreen: s.fullscreen }));
+  const { size, fullscreen, visible } = usePanelStore((s) => ({ size: s.size, fullscreen: s.fullscreen, visible: s.visible }));
 
   const [layerSize, setLayerSize] = useState(size);
+  const [displayStyle, setDisplayStyle] = useState({});
 
   const currentSize = fullscreen ? layerSize : size;
 
@@ -61,6 +62,12 @@ const PanelItem: React.FC<{ panel: PanelEntity }> = ({ panel }) => {
     return () => observer.disconnect();
   }, [fullscreen]);
 
+  useEffect(() => {
+    if (panel.keepDOM) {
+      setDisplayStyle({ display: visible ? 'block' : 'none' });
+    }
+  }, [visible]);
+
   return (
     <div
       className={clsx(
@@ -69,7 +76,7 @@ const PanelItem: React.FC<{ panel: PanelEntity }> = ({ panel }) => {
       )}
       key={panel.id}
       ref={ref}
-      style={{ ...panel.factory.style, ...panel.config.style, ...sizeStyle }}
+      style={{ ...displayStyle, ...panel.factory.style, ...panel.config.style, ...sizeStyle }}
     >
       {panel.resizable &&
         panelManager.config.resizeBarRender({

+ 14 - 0
packages/plugins/panel-manager-plugin/src/services/panel-factory.ts

@@ -30,6 +30,7 @@ const PANEL_SIZE_DEFAULT = 400;
 export interface PanelEntityState {
   size: number;
   fullscreen: boolean;
+  visible: boolean;
 }
 
 @injectable()
@@ -87,6 +88,18 @@ export class PanelEntity {
     return this.factory.resize !== undefined ? this.factory.resize : this.globalConfig.autoResize;
   }
 
+  get keepDOM() {
+    return this.factory.keepDOM;
+  }
+
+  get visible() {
+    return this.store.getState().visible;
+  }
+
+  set visible(next: boolean) {
+    this.store.setState({ visible: next });
+  }
+
   get layer() {
     return document.querySelector(
       this.mode ? '.gedit-flow-panel-layer-wrap-docked' : '.gedit-flow-panel-layer-wrap-floating'
@@ -109,6 +122,7 @@ export class PanelEntity {
       {
         size: this.factory.defaultSize || PANEL_SIZE_DEFAULT,
         fullscreen: this.factory.fullscreen || false,
+        ...(this.factory.keepDOM ? { visible: true } : {}),
       }
     );
 

+ 15 - 3
packages/plugins/panel-manager-plugin/src/services/panel-manager.ts

@@ -42,7 +42,12 @@ export class PanelManager {
 
     const sameKeyPanels = this.getPanels(area).filter((p) => p.key === key);
     if (!factory.allowDuplicates && sameKeyPanels.length) {
-      sameKeyPanels.forEach((p) => this.remove(p.id));
+      !factory.keepDOM && sameKeyPanels.forEach((p) => this.remove(p.id));
+    }
+
+    if (factory.keepDOM && sameKeyPanels.length) {
+      sameKeyPanels[0].visible = true;
+      return;
     }
 
     const panel = this.createPanel({
@@ -62,12 +67,19 @@ export class PanelManager {
   public close(key?: string) {
     const panels = this.getPanels();
     const closedPanels = key ? panels.filter((p) => p.key === key) : panels;
-    closedPanels.forEach((p) => this.remove(p.id));
+    closedPanels.forEach((panel) => {
+      if (panel.keepDOM) {
+        panel.visible = false;
+        return;
+      }
+
+      this.remove(panel.id)
+    });
     this.onPanelsChangeEvent.fire();
   }
 
   private trim(area: Area) {
-    const panels = this.getPanels(area);
+    const panels = this.getPanels(area).filter((p) => !p.keepDOM);
     const areaConfig = this.getAreaConfig(area);
     while (panels.length > areaConfig.max) {
       const removed = panels.shift();

+ 1 - 0
packages/plugins/panel-manager-plugin/src/types.ts

@@ -20,6 +20,7 @@ export interface PanelFactory<T extends any> {
   /** Allows multiple panels with the same key to be rendered simultaneously  */
   allowDuplicates?: boolean;
   resize?: boolean;
+  keepDOM?: boolean;
   render: (props: T) => React.ReactNode;
 }