How to use DetectOverflow or Custom Middleware from Floating UI JS with Serverless Vanilla JS?

396 Views Asked by At

I am dealing with an overflow problem on my div when dragging my Floating UI tooltips. Floating UI has a solution for this natively called detectOverflow, but I've had issues trying to prevent it from erroring out. I believe I am having issues with using Custom Middleware with Floating UI as a whole.

I've got a .NET project where I am using Floating UI JS to show tooltips on draggable tag elements. They display information regarding my element types. The draggable are floating on top of a element where they are contained in. Importing Floating UI the traditional way has not worked for me. Even when setting the <src type="module> (this has given me different complications with my code as well). So, I import from the FLoating UI CDN in my index.cshtml file the traditional Vanilla JS way:

<script src='https://cdn.jsdelivr.net/npm/@Html.Raw("@")floating-ui/[email protected]'></script>
<script src='https://cdn.jsdelivr.net/npm/@Html.Raw("@")floating-ui/[email protected]'></script>

In Script.js, a different file in the directory I utilize computePosition from Floating UI.js:

FloatingUIDOM.computePosition(draggableElement, tooltipElement, {
    placement: placement,
    middleware: [
        FloatingUICore.offset(5),
        FloatingUICore.flip(),
        FloatingUICore.shift({ padding: 5 }),
        FloatingUICore.arrow({ element: arrowElement }),
    ],
}).then(({ x, y, placement, middlewareData }) => {

    Object.assign(tooltipElement.style, {
        left: `${x}px`,
        top: `${y}px`,
    });

    // Accessing the data
    const { x: arrowX, y: arrowY } = middlewareData.arrow;

    const staticSide = {
        top: 'bottom',
        right: 'left',
        bottom: 'top',
        left: 'right',
    }[placement.split('-')[0]];

    Object.assign(arrowElement.style, {
        left: arrowX != null ? `${arrowX}px` : '',
        top: arrowY != null ? `${arrowY}px` : '',
        right: '',
        bottom: '',
        [staticSide]: '-4px',
    });
});

This works great for me and correctly places the tooltips with its respective draggableElement. Notice that in order for me to use ComputePosition properly I had to prefix with FloatingUIDom. in order to avoid console errors. However, when I try to use detectOverflow like so,

const detectLabelOverflow = {
    name: 'detectLabelOverflow',
    async fn(state) {
      const overflow = await FloatingUIDOM.detectOverflow(state, {
        boundary: document.querySelector("#panzoomRect")
        //boundary: document.querySelector('#partialDiv')
      });
      return {};
    },
  };


FloatingUIDOM.computePosition(draggableElement, tooltipElement, {
    placement: placement,
    middleware: [
        FloatingUICore.offset(5),
        FloatingUICore.flip(),
        FloatingUICore.shift({ padding: 5 }),
        FloatingUICore.arrow({ element: arrowElement }),
        [detectLabelOverflow]
    ],
}).then(({ x, y, placement, middlewareData }) => {

    Object.assign(tooltipElement.style, {
        left: `${x}px`,
        top: `${y}px`,
    });

    // Accessing the data
    const { x: arrowX, y: arrowY } = middlewareData.arrow;

    const staticSide = {
        top: 'bottom',
        right: 'left',
        bottom: 'top',
        left: 'right',
    }[placement.split('-')[0]];

    Object.assign(arrowElement.style, {
        left: arrowX != null ? `${arrowX}px` : '',
        top: arrowY != null ? `${arrowY}px` : '',
        right: '',
        bottom: '',
        [staticSide]: '-4px',
    });
});

I run into this error, without any extra info. I understand core is the one of the CDN import files that house FLoating UI:

[email protected]:1 Uncaught (in promise) TypeError: p is not a function at t.computePosition ([email protected]:1:5480)

Clicking on that error reveals this, where the error is at line 16 , {x: h, y: y, data: x, reset: w} = await p({:

t.computePosition = async(t,e,n)=>{
        const {placement: i="bottom", strategy: o="absolute", middleware: r=[], platform: a} = n
          , l = r.filter(Boolean)
          , s = await (null == a.isRTL ? void 0 : a.isRTL(e));
        let f = await a.getElementRects({
            reference: t,
            floating: e,
            strategy: o
        })
          , {x: c, y: u} = b(f, i, s)
          , m = i
          , d = {}
          , g = 0;
        for (let n = 0; n < l.length; n++) {
            const {name: r, fn: p} = l[n]
              , {x: h, y: y, data: x, reset: w} = await p({
                x: c,
                y: u,
                initialPlacement: i,
                placement: m,
                strategy: o,
                middlewareData: d,
                rects: f,
                platform: a,
                elements: {
                    reference: t,
                    floating: e
                }
            });
            c = null != h ? h : c,
            u = null != y ? y : u,
            d = {
                ...d,
                [r]: {
                    ...d[r],
                    ...x
                }
            },
            w && g <= 50 && (g++,
            "object" == typeof w && (w.placement && (m = w.placement),
            w.rects && (f = !0 === w.rects ? await a.getElementRects({
                reference: t,
                floating: e,
                strategy: o
            }) : w.rects),
            ({x: c, y: u} = b(f, m, s))),
            n = -1)
        }
        return {
            x: c,
            y: u,
            placement: m,
            strategy: o,
            middlewareData: d
        }
    }

Lastly, I understood that detectOverflow was considered custom middleware and tried to see if I could just get that to function, but I would get the same error as well:

const shiftByOnePixel = {
  name: 'shiftByOnePixel',
  fn({x, y}) {
    return {
      x: x + 1,
      y: y + 1,
    };
  },
};

FloatingUIDOM.computePosition(draggableElement, tooltipElement, {
    placement: placement,
    middleware: [
        FloatingUICore.offset(5),
        FloatingUICore.flip(),
        FloatingUICore.shift({ padding: 5 }),
        FloatingUICore.arrow({ element: arrowElement }),
        [shiftByOnePixel]
    ],
}).then(({ x, y, placement, middlewareData }) => {

    Object.assign(tooltipElement.style, {
        left: `${x}px`,
        top: `${y}px`,
    });

    // Accessing the data
    const { x: arrowX, y: arrowY } = middlewareData.arrow;

    const staticSide = {
        top: 'bottom',
        right: 'left',
        bottom: 'top',
        left: 'right',
    }[placement.split('-')[0]];

    Object.assign(arrowElement.style, {
        left: arrowX != null ? `${arrowX}px` : '',
        top: arrowY != null ? `${arrowY}px` : '',
        right: '',
        bottom: '',
        [staticSide]: '-4px',
    });
});
0

There are 0 best solutions below