allotment icon indicating copy to clipboard operation
allotment copied to clipboard

preferredSize do not work

Open huoyingyangjie opened this issue 1 year ago • 8 comments

Hi, i try it to create layout like vscode, but 'preferredSize={280}' don't work at 'E' section.

           <Allotment vertical={true}>
                <Allotment.Pane maxSize={30} minSize={30}>
                          <div>A</div>
                </Allotment.Pane>
                <Allotment.Pane>
                    <Allotment>
                        <Allotment.Pane maxSize={48} minSize={48}>
                            <div>B</div>
                        </Allotment.Pane>
                        <Allotment.Pane preferredSize={280} minSize={170} snap={true}>
                            <div>C</div>
                        </Allotment.Pane>
                        <Allotment.Pane>
                            <Allotment vertical={true}>
                                <Allotment.Pane>
                                    <div>D</div>
                                </Allotment.Pane>
                                {/*at here, preferredSize={280} don't work*/}
                                <Allotment.Pane preferredSize={280} minSize={120} snap={true}>
                                    <div>E</div>
                                </Allotment.Pane>
                            </Allotment>
                        </Allotment.Pane>
                        <Allotment.Pane preferredSize={280} minSize={170} snap={true}>
                            <div>F</div>
                        </Allotment.Pane>
                    </Allotment>
                </Allotment.Pane>
                <Allotment.Pane maxSize={22} minSize={22}>
                    <div>G</div>
                </Allotment.Pane>
            </Allotment>

huoyingyangjie avatar Mar 30 '23 08:03 huoyingyangjie

I trace code and debug, found it caused container has no 'width' and 'height'.

 useIsomorphicLayoutEffect(() => {
      if (!dimensionsInitialized) {
        const { height, width } = containerRef.current.getBoundingClientRect();  // here
        splitViewRef.current?.layout(vertical ? height : width);
        layoutService.current.setSize(vertical ? height : width);
        setDimensionsInitialized(true);
      }
    }, [dimensionsInitialized, vertical]);

Since the mounting of React is from the inside to the outside,so container has no width and height

huoyingyangjie avatar Mar 31 '23 06:03 huoyingyangjie

I fixed it by below code:

diff --git a/src/allotment.tsx b/src/allotment.tsx
index ea2385f..c555e20 100644
--- a/src/allotment.tsx
+++ b/src/allotment.tsx
@@ -29,6 +29,17 @@ function isPane(item: React.ReactNode | typeof Pane): item is typeof Pane {
   return (item as any).type.displayName === "Allotment.Pane";
 }
 
+function containAllotment(item: React.ReactNode | typeof Allotment): item is typeof Allotment {
+  let result = false
+  React.Children.toArray((item as any).props?.children).map((child)=>{
+      if((child as any).type.displayName === "Allotment")
+      {
+        result = true
+      }
+  })
+  return result
+}
+
 function isPaneProps(props: AllotmentProps | PaneProps): props is PaneProps {
   return (
     (props as PaneProps).minSize !== undefined ||
@@ -145,6 +156,7 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
     const splitViewViewRef = useRef(new Map<React.Key, HTMLElement>());
     const layoutService = useRef<LayoutService>(new LayoutService());
     const views = useRef<PaneView[]>([]);
+    const [paneWithAllotmentInitialized, setPaneWithAllotmentInitialized] = useState(false)
 
     const [dimensionsInitialized, setDimensionsInitialized] = useState(false);
 
@@ -463,6 +475,7 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
         const { height, width } = containerRef.current.getBoundingClientRect();
         splitViewRef.current?.layout(vertical ? height : width);
         layoutService.current.setSize(vertical ? height : width);
+        setPaneWithAllotmentInitialized(true);
         setDimensionsInitialized(true);
       }
     }, [dimensionsInitialized, vertical]);
@@ -503,16 +516,23 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
             if (isPane(child)) {
               splitViewPropsRef.current.set(key, child.props);
 
-              return React.cloneElement(child as React.ReactElement, {
-                key: key,
-                ref: (el: HTMLElement | null) => {
-                  if (el) {
-                    splitViewViewRef.current.set(key, el);
-                  } else {
-                    splitViewViewRef.current.delete(key);
-                  }
-                },
-              });
+              if(!paneWithAllotmentInitialized && containAllotment(child) && !defaultSizes)
+              {
+                  return null
+              }
+              else
+              {
+                return React.cloneElement(child as React.ReactElement, {
+                  key: key,
+                  ref: (el: HTMLElement | null) => {
+                    if (el) {
+                      splitViewViewRef.current.set(key, el);
+                    } else {
+                      splitViewViewRef.current.delete(key);
+                    }
+                  },
+                });
+              }
             } else {
               return (
                 <Pane

huoyingyangjie avatar Mar 31 '23 08:03 huoyingyangjie

@johnwalley would be nice to include it into nearest release

AndreiDziubiankou avatar Apr 25 '23 11:04 AndreiDziubiankou

Hey @johnwalley I am also encountering this issue on v1.19.0 and was wondering if you have any plans to include the fix above in the newest release? Cheers!

nkhi avatar May 30 '23 19:05 nkhi

@johnwalley any updates about it?

AndreiDziubiankou avatar Jun 14 '23 07:06 AndreiDziubiankou

Hi, I also encountered the same problem! Here is my solution

const ref = useRef<any>();
useEffect(() => {
  setTimeout(() => ref.current.reset(), 0);
}, []);
<Allotment  ref={ref}>
    <Allotment.Pane
      visible={visible}
      preferredSize={200}
      minSize={200}
      maxSize={400}
    >
      <div></div>
    </Allotment.Pane>
    <div></div>
</Allotment>

tpc-ht avatar Aug 23 '23 03:08 tpc-ht

🤷‍♂️ The preferredSize does not seem to work anymore at all. Also, @tpc-ht's suggestion did not work for me.

✅ I had better results with a combination of defaultSizes and proportionalLayout=false in addition to a onReset. This is a minimal example (without optimized callbacks etc.)

const ref = useRef<AllotmentHandle>(null)
const sizes = [200, 0]} // Set first size and "ignore" second

const handleReset = () => {
  ref.current?.resize(sizes)}  // mimics the doubleClick behavior as before
}

return (
  <Allotment
    ref={ref}                  // get access to resize(...)
    proportionalLayout={false} // use pixel sizes (not percentage)
    defaultSizes={sizes}       // Set first size and "ignore" second
    onReset={handleReset}      // override reset to use "defaultSizes"
  >
    // ... content, panes, ...
  </Allotment>
)

Wrapping this into a component actually restores the preferredSize behavior until it is fixed in the lib.

ghost avatar Feb 19 '24 11:02 ghost

Also seeing that preferredSize is not respected on a nested Allotment since version 1.18.0 onwards.

Heres a repro of the issue: https://codesandbox.io/p/sandbox/nested-forked-v4j9qz

My simple fix for now was to downgrade to v1.17.1, but I'd like to contribute if possible

mattrussell36 avatar May 21 '24 08:05 mattrussell36

Thanks everyone for reporting this.

I've reverted the commit which appears to trigger the problem and published a new package v1.20.2.

If you get a chance to test it and report back that would be super helpful.

johnwalley avatar May 22 '24 10:05 johnwalley

@johnwalley v1.20.2 is working for me

mattrussell36 avatar May 22 '24 13:05 mattrussell36

@johnwalley same for me. works fine now

AndreiDziubiankou avatar May 28 '24 12:05 AndreiDziubiankou