floating-ui arrow and scroll issue

190 views Asked by At

I want to build a popover for my RichText editor so that when I select a piece of text, a popover appears with some buttons like bold, italic etc. It should change it's position automatically when more/less text is selected. My current problems are:

  • popover flips its position only when scrolling the main scrollbar from body tag, not the one that comes from the container with my editor. When I scroll inside the editor container, the tooltip does not change it positions to match the position of a selected text which changes due to scrolling
  • I tried to add an arrow but it positioning is wrong (too far from the floating element and don't flip as well when popover flips

Here is the relevant code. Do you have any suggestions how to fix above issues?

export const ControlledBubbleMenu = ({ editor, open, children }: Props) => {
  const arrowRef = useRef(null);
  const {
    x,
    y,
    strategy,
    floatingStyles,
    refs: { reference, setReference, setFloating },
    middlewareData,
    context,
  } = useFloating({
    strategy: 'fixed',
    whileElementsMounted: autoUpdate,
    placement: 'bottom',
    middleware: [
      offset({ mainAxis: 8 }),
      flip({
        // padding: 8,
        boundary: editor.options.element,
        fallbackPlacements: [
          'top',
          'top-start',
          'bottom-start',
          'top-end',
          'bottom-end',
        ],
      }),
      //   shift(),
      arrow({
        element: arrowRef,
      }),
    ],
  });

  useLayoutEffect(() => {
    setReference({
      getBoundingClientRect() {
        const { ranges } = editor.state.selection;
        const from = Math.min(...ranges.map((range) => range.$from.pos));
        const to = Math.max(...ranges.map((range) => range.$to.pos));

        if (isNodeSelection(editor.state.selection)) {
          const node = editor.view.nodeDOM(from) as HTMLElement;

          if (node) {
            return node.getBoundingClientRect();
          }
        }

        return posToDOMRect(editor.view, from, to);
      },
    });
  }, [reference, editor.state.selection]);

  if (!open) {
    return null;
  }

  return (
    <FloatingFocusManager context={context} modal={false}>
      <div className='bg-card' ref={setFloating} style={floatingStyles}>
        {children}
        <div
          ref={arrowRef}
          className='absolute h-[8px] w-[8px] rotate-45 bg-card'
          style={{
            left: middlewareData.arrow?.x,
            top: middlewareData.arrow?.y,
          }}
        ></div>
      </div>
    </FloatingFocusManager>
  );
};
0

There are 0 answers