romkor / svelte-portal

Svelte component for rendering outside the DOM of parent component
https://svelte.dev/repl/407576d4fa984cfb97dcdd3da98e833e
MIT License
444 stars 22 forks source link

Element targets assume window context #159

Open HexaCubist opened 2 years ago

HexaCubist commented 2 years ago

The type check here assumes that the target element is in the same window context as the script:

https://github.com/romkor/svelte-portal/blob/master/src/Portal.svelte#L25

This might not always be the case, such as running across iframes or windows. See this StackOverflow answer: https://stackoverflow.com/a/26251098/3902950

Iframes have their own copy of HTMLElement, so target instanceof HTMLElement returns false, while target instanceof otherwindow.HTMLElement returns true.

Open to ideas on how this might be best implemented - perhaps with another optional property specifying the reference window?

  /**
   * Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}> or <div use:portal={document.body} window={otherwindowcontext}>
   *
   * @param {HTMLElement} el
   * @param {HTMLElement|string} target DOM Element or CSS Selector
   * @param {Window} [window=window] Target window DOM document
   */
HexaCubist commented 2 years ago

Relevant: #142 - the workaround here will solve this issue too, but it might be neater to allow setting the context as a parameter

HexaCubist commented 2 years ago

Solved this issue for my project with a function found on Stackoverflow:

// Source: https://stackoverflow.com/a/20532809/3902950
const deriveWindow = (elm: HTMLElement | null) => {
    return elm?.ownerDocument?.defaultView || false;
};

The above returns the window context of the given element, which can then be used to:

const tWindow = deriveWindow(target);
if (tWindow && target instanceof tWindow.HTMLElement) {

See implementation here (this version of the library is ported to Typescript): https://github.com/Ranga-Auaha-Ako/canvas-grid-builder/blob/c7b2b75c0b8ecc2413abd1c65bf47f63281b5757/src/lib/portal/portal.svelte