INIT
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
export { default as Portal } from "./portal.svelte";
|
||||
export type { PortalProps } from "./types.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { default as Portal } from "./portal.svelte";
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
const { children }: { children?: Snippet } = $props();
|
||||
</script>
|
||||
|
||||
{#key children}
|
||||
{@render children?.()}
|
||||
{/key}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { Snippet } from "svelte";
|
||||
type $$ComponentProps = {
|
||||
children?: Snippet;
|
||||
};
|
||||
declare const PortalConsumer: import("svelte").Component<$$ComponentProps, {}, "">;
|
||||
type PortalConsumer = ReturnType<typeof PortalConsumer>;
|
||||
export default PortalConsumer;
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<script lang="ts">
|
||||
import { getAllContexts, mount, unmount } from "svelte";
|
||||
import { DEV } from "esm-env";
|
||||
import { watch } from "runed";
|
||||
import PortalConsumer from "./portal-consumer.svelte";
|
||||
import type { PortalProps } from "./types.js";
|
||||
import { isBrowser } from "../../../internal/is.js";
|
||||
import { resolvePortalToProp } from "../config/prop-resolvers.js";
|
||||
|
||||
let { to: toProp, children, disabled }: PortalProps = $props();
|
||||
|
||||
const to = resolvePortalToProp(() => toProp);
|
||||
const context = getAllContexts();
|
||||
|
||||
let target = $derived(getTarget());
|
||||
|
||||
function getTarget() {
|
||||
if (!isBrowser || disabled) return null;
|
||||
|
||||
let localTarget: Element | null = null;
|
||||
|
||||
if (typeof to.current === "string") {
|
||||
const target = document.querySelector(to.current);
|
||||
if (DEV && target === null) {
|
||||
throw new Error(`Target element "${to.current}" not found.`);
|
||||
}
|
||||
localTarget = target;
|
||||
} else {
|
||||
localTarget = to.current;
|
||||
}
|
||||
|
||||
if (DEV && !(localTarget instanceof Element)) {
|
||||
const type = localTarget === null ? "null" : typeof localTarget;
|
||||
throw new TypeError(
|
||||
`Unknown portal target type: ${type}. Allowed types: string (query selector) or Element.`
|
||||
);
|
||||
}
|
||||
|
||||
return localTarget;
|
||||
}
|
||||
|
||||
let instance: ReturnType<typeof mount> | null;
|
||||
|
||||
function unmountInstance() {
|
||||
if (instance) {
|
||||
unmount(instance);
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
watch([() => target, () => disabled], ([target, disabled]) => {
|
||||
if (!target || disabled) {
|
||||
unmountInstance();
|
||||
return;
|
||||
}
|
||||
instance = mount(PortalConsumer, {
|
||||
target: target,
|
||||
props: { children },
|
||||
context,
|
||||
});
|
||||
|
||||
return () => {
|
||||
unmountInstance();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if disabled}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { PortalProps } from "./types.js";
|
||||
declare const Portal: import("svelte").Component<PortalProps, {}, "">;
|
||||
type Portal = ReturnType<typeof Portal>;
|
||||
export default Portal;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import type { Snippet } from "svelte";
|
||||
export type PortalTarget = Element | string;
|
||||
export type PortalProps = {
|
||||
/**
|
||||
* Where to portal the content to.
|
||||
*
|
||||
* @default document.body
|
||||
*/
|
||||
to?: PortalTarget;
|
||||
/**
|
||||
* Disable portalling and render the component inline
|
||||
*
|
||||
* @defaultValue false
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* The children content to render within the portal.
|
||||
*/
|
||||
children?: Snippet;
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user