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',
});
});