Popper.js: how to set position fixed strategy with modifiers?
Asked Answered
D

0

9

I'm trying to implement a context menu using BlueprintJs Popover component; that uses Popper.js to position the popover, under the hood.

The problemis that: I have fixed elements and absolutely positioned elements (with transform css property set to translate3d - I believe these create new stacking contexts, possibly causing issues too) in the dom tree, above the context menu, that can not be changed. I've read somewhere in the Popper.js documentation, that I should use the fixed position strategy in this case.

Unfortunately BlueprintJs Popover does not allow me (as far as I know) to set Popper.js options, only modifiers.

So can the positioning strategy be changed with modifiers?

Here's the code and what I've tried:

import React, { useState } from 'react';
import { Popover, Position, Classes } from '@blueprintjs/core';

const getModifiers = (left, top) => {
  return {
    preventOverflow: { boundariesElement: 'viewport' },
    computeStyle: {
      // set to false to avoid using transform property to position element,
      // as that clashes with other transform: translate3d styles set earlier
      gpuAcceleration: false,

      // I could just overwrite the computeStyles fn, and use position fixed;
      // but I'd like to avoid that and let Popper.js do the coordinate arithmetics
      // fn: (data) => {
      //   return { 
      //     ...data, 
      //     styles: { 
      //       ...data.styles, 
      //       position: 'fixed',
      //       left: `${left}px`,
      //       top: `${top}px`,
      //     }
      // };
      // },
    },

    // here's where I try to change the position strategy using custom modifier
    changeStrategyWithModifier: {
      order: 0,
      enabled: true,
      name: 'changeStrategyWithModifier',
      phase: 'main',
      fn: (data) => {
        return {
          ...data,
          instance: {
            ...data.instance,
            options: {
              ...data.instance.options,
              positionFixed: true, // does not seem ot have any effect
              strategy: 'fixed', // does not seem ot have any effect
            },
          },
          state: {
            // reset set to true to restart process after changing strategy
            ...data.instance.state,
            reset: true, 
          },
          positionFixed: true, // does not seem ot have any effect
        };
      },
    },
  };
};

const ContextMenu = (props) => {
  const [isOpen, setOpen] = useState(false);
  const [offset, setOffset] = useState();
  const portalContainer = useGetPortalContainer();

  const handleCloseContextMenu = () => setOpen(false);

  const handleInteraction = () => setOpen(false);

  const handleOpenContextMenu = (mouseEvent) => {
    mouseEvent.preventDefault();
    setOffset({ left: mouseEvent.clientX, top: mouseEvent.clientY });
    setOpen(true);
  };

  const modifiers = getModifiers(offset.left, offset.top);

  return (
    <>
      <div className={Classes.CONTEXT_MENU_POPOVER_TARGET} style={offset}>
        <Popover
          isOpen={isOpen}
          onInteraction={handleInteraction}
          content={props.renderMenu(handleCloseContextMenu)}
          target={<div />}
          usePortal={true}
          portalContainer={portalContainer}
          position={Position.TOP_LEFT}
          modifiers={modifiers}
        />
      </div>
      {props.renderComponent(handleOpenContextMenu)}
    </>
  );
};
Deadlight answered 22/6, 2020 at 12:6 Comment(1)
I don't think this can answers the part about configuring BlueprintJs, however for anyone else who comes here and is just using Popper.js v2.x, it is possible to add the strategy: 'fixed' into the Popper.createPopper options: popper.js.org/docs/v2/faq/…Mccauley

© 2022 - 2024 — McMap. All rights reserved.