2024-04-11 17:18:07 +00:00
|
|
|
import { RefObject } from "inferno";
|
|
|
|
import {
|
|
|
|
DelegateInstance as TippyDelegateInstance,
|
|
|
|
Props as TippyProps,
|
|
|
|
Instance as TippyInstance,
|
|
|
|
delegate as tippyDelegate,
|
|
|
|
} from "tippy.js";
|
2023-06-21 22:28:24 +00:00
|
|
|
|
2024-04-11 17:18:07 +00:00
|
|
|
let instance: TippyDelegateInstance<TippyProps> | undefined;
|
|
|
|
const tippySelector = "[data-tippy-content]";
|
|
|
|
const shownInstances: Set<TippyInstance<TippyProps>> = new Set();
|
2024-04-13 15:15:29 +00:00
|
|
|
let instanceCounter = 0;
|
2023-06-21 22:28:24 +00:00
|
|
|
|
2024-04-11 17:18:07 +00:00
|
|
|
const tippyDelegateOptions: Partial<TippyProps> & { target: string } = {
|
|
|
|
delay: [500, 0],
|
|
|
|
// Display on "long press"
|
|
|
|
touch: ["hold", 500],
|
|
|
|
target: tippySelector,
|
|
|
|
onShow(i: TippyInstance<TippyProps>) {
|
|
|
|
shownInstances.add(i);
|
|
|
|
},
|
|
|
|
onHidden(i: TippyInstance<TippyProps>) {
|
|
|
|
shownInstances.delete(i);
|
|
|
|
},
|
2024-04-13 15:15:29 +00:00
|
|
|
onCreate() {
|
|
|
|
instanceCounter++;
|
|
|
|
},
|
|
|
|
onDestroy(i: TippyInstance<TippyProps>) {
|
|
|
|
// Tippy doesn't remove its onDocumentPress listener when destroyed.
|
|
|
|
// Instead the listener removes itself after calling hide for hideOnClick.
|
|
|
|
const origHide = i.hide;
|
|
|
|
// This silences the first warning when hiding a destroyed tippy instance.
|
|
|
|
// hide() is otherwise a noop for destroyed instances.
|
|
|
|
i.hide = () => {
|
|
|
|
i.hide = origHide;
|
|
|
|
};
|
|
|
|
},
|
2024-04-11 17:18:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export function setupTippy(root: RefObject<Element>) {
|
|
|
|
if (!instance && root.current) {
|
|
|
|
instance = tippyDelegate(root.current, tippyDelegateOptions);
|
|
|
|
}
|
2023-06-21 22:28:24 +00:00
|
|
|
}
|
|
|
|
|
2024-04-11 17:18:07 +00:00
|
|
|
export function cleanupTippy() {
|
2024-04-13 15:15:29 +00:00
|
|
|
// Hide tooltips for elements that are no longer connected to the document.
|
|
|
|
shownInstances.forEach(i => {
|
|
|
|
if (!i.reference.isConnected) {
|
|
|
|
console.assert(!i.state.isDestroyed, "hide called on destroyed tippy");
|
|
|
|
i.hide();
|
2024-04-11 17:18:07 +00:00
|
|
|
}
|
|
|
|
});
|
2024-04-13 15:15:29 +00:00
|
|
|
|
|
|
|
if (shownInstances.size || instanceCounter < 10) {
|
|
|
|
// Avoid randomly closing tooltips.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
instanceCounter = 0;
|
|
|
|
const current = instance?.reference ?? null;
|
|
|
|
// delegate from tippy.js creates tippy instances when needed, but only
|
|
|
|
// destroys them when the delegate instance is destroyed.
|
|
|
|
destroyTippy();
|
|
|
|
setupTippy({ current });
|
2024-04-11 17:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function destroyTippy() {
|
|
|
|
instance?.destroy();
|
|
|
|
instance = undefined;
|
2023-06-21 22:28:24 +00:00
|
|
|
}
|