open-webui/src/lib/components/common/RichTextInput/suggestions.ts
Timothy Jaeryang Baek 56a8973fa0 refac
2025-09-13 00:30:00 +04:00

85 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<string, any>([['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 components 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;
}
};
};
}