import tippy from 'tippy.js'; export function getSuggestionRenderer(Component: any, ComponentProps = {}) { return function suggestionRenderer() { let component = null; let container: HTMLDivElement | null = null; let popup: TippyInstance | null = null; let refEl: HTMLDivElement | null = null; // dummy reference return { onStart: (props: any) => { container = document.createElement('div'); container.className = 'suggestion-list-container'; document.body.appendChild(container); // mount Svelte component component = new Component({ target: container, props: { char: props?.text, command: (item) => { props.command({ id: item.id, label: item.label }); }, ...ComponentProps }, context: new Map([['i18n', ComponentProps?.i18n]]) }); // Create a tiny reference element so outside taps are truly "outside" refEl = document.createElement('div'); Object.assign(refEl.style, { position: 'fixed', left: '0px', top: '0px', width: '0px', height: '0px' }); document.body.appendChild(refEl); popup = tippy(refEl, { getReferenceClientRect: props.clientRect as any, appendTo: () => document.body, content: container, interactive: true, trigger: 'manual', theme: 'transparent', placement: 'top-start', offset: [-10, -2], arrow: false }); popup?.show(); }, onUpdate: (props: any) => { if (!component) return; component.$set({ query: props.query }); if (props.clientRect && popup) { popup.setProps({ getReferenceClientRect: props.clientRect as any }); } }, onKeyDown: (props: any) => { // forward to the Svelte component’s handler // (expose this from component as `export function onKeyDown(evt)`) // @ts-ignore return component?._onKeyDown?.(props.event) ?? false; }, onExit: () => { popup?.destroy(); popup = null; component?.$destroy(); component = null; if (container?.parentNode) container.parentNode.removeChild(container); container = null; if (refEl?.parentNode) refEl.parentNode.removeChild(refEl); refEl = null; } }; }; }