This commit is contained in:
eewing
2026-02-17 14:10:16 -06:00
parent 2bca5834c5
commit cf73cd3b4c
11246 changed files with 1690552 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
export { default as Portal } from "./portal.svelte";
export type { PortalProps } from "./types.js";
+1
View File
@@ -0,0 +1 @@
export { default as Portal } from "./portal.svelte";
@@ -0,0 +1,9 @@
<script lang="ts">
import type { Snippet } from "svelte";
const { children }: { children?: Snippet } = $props();
</script>
{#key children}
{@render children?.()}
{/key}
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1 @@
export {};