Move the portal root to the bottom of the target after initial render
Fixes #78
This commit is contained in:
24
src/lib/components/portal/portal.test.ts
vendored
24
src/lib/components/portal/portal.test.ts
vendored
@@ -3,6 +3,7 @@ import { render } from "@testing-library/svelte";
|
||||
import Portal from "./Portal.svelte";
|
||||
import PortalGroup from "./PortalGroup.svelte";
|
||||
import { click } from "$lib/test-utils/interactions";
|
||||
import { tick } from "svelte";
|
||||
|
||||
function getPortalRoot() {
|
||||
return document.getElementById('headlessui-portal-root')!
|
||||
@@ -333,3 +334,26 @@ it('should cleanup the Portal properly when Svelte would not detach it', async (
|
||||
expect(getPortalRoot()).not.toBe(null)
|
||||
expect(getPortalRoot().childNodes).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should move the Portal last during initial render', async () => {
|
||||
expect(getPortalRoot()).toBe(null)
|
||||
|
||||
// We need to use a custom target because of the implementation of
|
||||
// render() in the testing library
|
||||
render(svelte`
|
||||
<script>
|
||||
let target = document.body.firstChild;
|
||||
</script>
|
||||
|
||||
<PortalGroup {target}>
|
||||
<Portal>Portal</Portal>
|
||||
</PortalGroup>
|
||||
<main>Main</main>
|
||||
`)
|
||||
|
||||
await tick();
|
||||
|
||||
expect(document.body.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div> <main>Main</main><div>Portal</div></div>"`
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { tick } from "svelte";
|
||||
|
||||
export function portal(
|
||||
element: HTMLElement,
|
||||
target: HTMLElement | null | undefined
|
||||
) {
|
||||
if (target) {
|
||||
target.append(element);
|
||||
// During initial render, the "portal" might be constructed before
|
||||
// the root component has even attached, causing the portal to not work.
|
||||
// This is a workaround for this issue--it can't guarantee the portal is
|
||||
// **always** last, but it should catch the normal cases.
|
||||
tick().then(() => {
|
||||
if (target && element !== target.lastChild) {
|
||||
target.appendChild(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
update(newTarget: HTMLElement) {
|
||||
|
||||
Reference in New Issue
Block a user