fix: Fix Tooltip memory leaking and type define (#21969)

This commit is contained in:
Shirasawa
2026-02-28 14:01:28 -05:00
committed by GitHub
parent 144c0f3d76
commit 242b3f0c01
+32 -20
View File
@@ -3,63 +3,75 @@
import { onDestroy } from 'svelte'; import { onDestroy } from 'svelte';
import tippy from 'tippy.js'; import tippy, {
type Instance as TippyInstance,
type Placement as TippyPlacement,
type Props as TippyProps
} from 'tippy.js';
export let elementId = ''; export let elementId = '';
export let as = 'div'; export let as = 'div';
export let className = 'flex'; export let className = 'flex';
export let placement = 'top'; export let placement: TippyPlacement = 'top';
export let content = `I'm a tooltip!`; export let content = `I'm a tooltip!`;
export let touch = true; export let touch = true;
export let theme = ''; export let theme = '';
export let offset = [0, 4]; export let offset: TippyProps['offset'] = [0, 4];
export let allowHTML = true; export let allowHTML = true;
export let tippyOptions = {}; export let tippyOptions: Partial<TippyProps> = {};
export let interactive = false; export let interactive = false;
export let onClick = () => {}; export let onClick = () => {};
let tooltipElement; let tooltipElement: HTMLElement | null = null;
let tooltipInstance; let tooltipInstance: TippyInstance | null = null;
function destroyInstance() {
if (tooltipInstance) {
tooltipInstance.destroy();
tooltipInstance = null;
}
}
$: if (tooltipElement && (content || elementId)) { $: if (tooltipElement && (content || elementId)) {
let tooltipContent = null; let tooltipContent: string | Element | DocumentFragment | null = null;
if (elementId) { if (elementId) {
tooltipContent = document.getElementById(`${elementId}`); tooltipContent = document.getElementById(elementId);
} else { } else {
tooltipContent = DOMPurify.sanitize(content); tooltipContent = DOMPurify.sanitize(content);
} }
// After the element changes, the old instance must be destroyed, otherwise the detached tippy floating DOM will be left behind
if (tooltipInstance && tooltipInstance.reference !== tooltipElement) {
destroyInstance();
}
if (tooltipInstance) { if (tooltipInstance) {
tooltipInstance.setContent(tooltipContent); tooltipInstance.setContent(tooltipContent ?? '');
} else { } else {
if (content) { if (content) {
tooltipInstance = tippy(tooltipElement, { tooltipInstance = tippy(tooltipElement, {
content: tooltipContent, content: tooltipContent ?? '',
placement: placement, placement,
allowHTML: allowHTML, allowHTML,
touch: touch, touch,
...(theme !== '' ? { theme } : { theme: 'dark' }), ...(theme !== '' ? { theme } : { theme: 'dark' }),
arrow: false, arrow: false,
offset: offset, offset,
...(interactive ? { interactive: true } : {}), ...(interactive ? { interactive: true } : {}),
...tippyOptions ...tippyOptions
}); });
} }
} }
} else if (tooltipInstance && content === '') { } else if (tooltipInstance && content === '') {
if (tooltipInstance) { destroyInstance();
tooltipInstance.destroy();
}
} }
onDestroy(() => { onDestroy(() => {
if (tooltipInstance) { destroyInstance();
tooltipInstance.destroy();
}
}); });
</script> </script>