How can I add props to a compound child component without using top level api methods?

Viewed 41

I am attempting to create a Panel component that has the option to be wrapped in a PanelGroup component. The PanelGroup components main function is the query the children Panel components and determine if certain conditions so it can add a z-index prop to each of them according to the conditions.

  1. Is it a left, right, top or bottom positioned Panel
  2. Is it a nested Panel

Each condition will require a z-index that may be higher than the others and also placed in front of the highest z-index found on the page. I would like to be able to iterate though the children inside a useEffect and after logic is ran to determine the hierarchy, add the z-index to each child as a prop. I have attempted to use React.Children mapping through and using cloneElement to add the z-index, however the issue is this method must be called inside the render/return and when a second panel is opened it causes any other panel that is open to close and open again. Is there a way to update the props without using the top level React API?

PanelGroup API

<PanelGroup>
  <Panel
    id={'1'}
    open={open1}
    onClosed={handleClose1}
    controller={true}
    renderPortal={true}
    position={PanelPosition.RIGHT}
  >
    <div>
      <h2>Panel Slide Left</h2>
      <button onClick={handleClose1}>Close</button>
    </div>
  </Panel>
  <Panel
    id={'2'}
    open={open2}
    onClosed={handleClose2}
    controller={true}
    renderPortal={true}
    position={PanelPosition.LEFT}
  >
    <div>
      <h2>Panel Slide Right</h2>
      <button onClick={handleClose2}>Close</button>
    </div>
  </Panel>
</PanelGroup>

This is what I tried which does not work

const PanelGroup = ({
  children
}: PanelGroupProp): JSX.Element => {

  const [highestZIndex, setHighestZIndex] = React.useState(null);

  /**
   * Handles finding the highest index on the page after render. This value
   * will be used as the benchmark to set the z-index of the panel
   * components managed by this component.
   */
  React.useEffect(() => {
    const highestIndex = getHighestZIndex();

    setHighestZIndex(highestIndex);
  }, []);

  const renderGroupPanelChildren = (children): React.ReactElement => {
    let incrementor = highestZIndex + 1;

    return (
      <React.Fragment>
        {React.Children.map(children || null, (child) => {
          const newProps = {...child.props, ZIndex: incrementor };

          incrementor++;

          return <child.type {...newProps } key={getGuid()} />;
        })}
      </React.Fragment>
    );
  };

  return (
    <>
      <PanelOverlay visibility={false} />
      {renderGroupPanelChildren(children)}
    </>
  );
};

I would like to find a way to do something like:

const PanelGroupComponent = ({
  children
}: PanelGroupProp): JSX.Element => {

  const [highestZIndex, setHighestZIndex] = React.useState(null);
  const [elements, setElements] = React.useState(null);

  /**
   * Handles finding the highest index on the page after render. This value
   * will be used as the benchmark to set the z-index of the panel
   * components managed by this component.
   */
  React.useEffect(() => {
    const highestIndex = getHighestZIndex();

    setHighestZIndex(highestIndex);
  }, []);

  React.useEffect(() => {
    // logic to set z-index's ....
    const elements .... 
    
    setElements(elements);
    
  }, [highestIndex]);

  return (
    <>
      <PanelOverlay visibility={false} />
      {elements}
    </>
  );
};
0 Answers
Related