| | import { mount, unmount } from 'svelte'; |
| | import { createClassComponent } from 'svelte/legacy'; |
| |
|
| | 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; |
| |
|
| | return { |
| | onStart: (props: any) => { |
| | container = document.createElement('div'); |
| | container.className = 'suggestion-list-container'; |
| | document.body.appendChild(container); |
| |
|
| | |
| | component = createClassComponent({ |
| | component: Component, |
| | target: container, |
| | props: { |
| | char: props?.text, |
| | query: props?.query, |
| | command: (item) => { |
| | props.command({ id: item.id, label: item.label }); |
| | }, |
| | ...ComponentProps |
| | }, |
| | context: new Map<string, any>([['i18n', ComponentProps?.i18n]]) |
| | }); |
| |
|
| | |
| | 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, |
| | popperOptions: { |
| | strategy: 'fixed', |
| | modifiers: [ |
| | { |
| | name: 'preventOverflow', |
| | options: { |
| | boundary: 'viewport', |
| | altAxis: true, |
| | tether: true, |
| | padding: 8 |
| | } |
| | }, |
| | { |
| | name: 'flip', |
| | options: { |
| | boundary: 'viewport', |
| | fallbackPlacements: ['top-end', 'bottom-start', 'bottom-end'] |
| | } |
| | }, |
| | |
| | { name: 'computeStyles', options: { adaptive: true } } |
| | ] |
| | }, |
| | |
| | interactiveBorder: 8 |
| | }); |
| | popup?.show(); |
| | }, |
| |
|
| | onUpdate: (props: any) => { |
| | if (!component) return; |
| |
|
| | component.$set({ |
| | query: props.query, |
| | command: (item) => { |
| | props.command({ id: item.id, label: item.label }); |
| | } |
| | }); |
| |
|
| | if (props.clientRect && popup) { |
| | popup.setProps({ getReferenceClientRect: props.clientRect as any }); |
| | } |
| | }, |
| |
|
| | onKeyDown: (props: any) => { |
| | |
| | |
| | |
| | return component?._onKeyDown?.(props.event) ?? false; |
| | }, |
| |
|
| | onExit: () => { |
| | popup?.destroy(); |
| | popup = null; |
| |
|
| | try { |
| | component.$destroy(); |
| | } catch (e) { |
| | console.error('Error unmounting component:', e); |
| | } |
| |
|
| | component = null; |
| |
|
| | if (container?.parentNode) container.parentNode.removeChild(container); |
| | container = null; |
| |
|
| | if (refEl?.parentNode) refEl.parentNode.removeChild(refEl); |
| | refEl = null; |
| | } |
| | }; |
| | }; |
| | } |
| |
|