/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { h, getRenderingRef } from "@stencil/core";
function customTemplate(tpl, props) {
    // Wrap the h pragma, then we can know if we're using Stencil's
    // jsx renderer or a different one
    let hCalled = false;
    const hWrap = (...args) => {
        hCalled = true;
        return h(...args);
    };
    let tplResult = tpl ? tpl(hWrap, ...props) : undefined;
    const renderRef = getRenderingRef();
    // Using stencil renderer - return that now
    if (tplResult &&
        (hCalled || (typeof tplResult === 'object' && '$attrs$' in tplResult))) {
        return tplResult;
    }
    // Template is either Element, string or using a custom rendering method
    if (tplResult &&
        renderRef &&
        renderRef.customRenderer &&
        typeof tplResult === 'object' &&
        !('$attrs$' in tplResult) &&
        !(tplResult instanceof Element) &&
        typeof tplResult !== 'string' &&
        !hCalled) {
        // template result is jsx *not* from Stencil.
        // Render it now and output it later.
        const templateEle = document.createElement('template');
        const result = renderRef.customRenderer(tplResult, templateEle.content);
        // custom rendering can render to the templateEle OR return a Promise<string>
        tplResult = result && result['then'] ? result : templateEle;
    }
    return {
        ref: (d) => {
            if (!d)
                return;
            if (tplResult instanceof Element) {
                // custom rendered an element
                d.replaceChildren();
                d.append(tplResult['content'] || tplResult);
            }
            else if (tplResult['then']) {
                // custom rendered a promise. Most likely within SSR.
                tplResult
                    .then((res) => (d.innerHTML = res))
                    .catch((e) => console.error(e));
            }
        },
        innerHTML: typeof tplResult === 'string' ? tplResult : undefined,
    };
}
/**
 * A functional component to handle custom rendering.
 * Usage:
 *  @Prop() template = (_createElement: typeof h, exampleArg1: number, exampleArg2: boolean) => { if (exampleArg1) return <button>yay</button }
 *  // Optional
 * @Prop() customRenderer: CustomRenderer
 *
 * <CustomRender
 *   parentTag='div'
 *   attrs={{ onClick: e => this.handleClick(e), class: 'button-wrapper' }}
 *   template={this.template}
 *   args={[3, true]}
 * />
 *
 * @param props - renderer template function, arguments to pass to the renderer function, parental wrapper tag (and attributes)
 * @param children - other virtual nodes to render
 * @returns a jsx vnode
 */
export function CustomRender(props, children) {
    const { parentTag, attrs, template, args } = props;
    const templateResult = customTemplate(template, args);
    const templateAttrs = templateResult['ref'] ? templateResult : {};
    const TagName = parentTag;
    return (h(TagName, { ...attrs, ...templateAttrs }, children && children.length ? children : '', !!templateResult && !templateResult['ref'] && templateResult));
}
