From 0475ac2bc46ac787a444d09291e64cc0797b0cfd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C4=90=C4=83ng=20T=C3=BA?=
<68631458+ngdangtu-vn@users.noreply.github.com>
Date: Thu, 12 Jun 2025 21:58:16 +0700
Subject: [PATCH] improve `` container, add 2 new properties
- `asElement` allows to change Portal container element type
- `class` allows to set class for Portal container
---
packages/solid/web/src/index.ts | 14 ++++---
packages/solid/web/test/portal.spec.tsx | 50 +++++++++++++++++++++++++
2 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/packages/solid/web/src/index.ts b/packages/solid/web/src/index.ts
index c9d6fa00..9e3c1c31 100644
--- a/packages/solid/web/src/index.ts
+++ b/packages/solid/web/src/index.ts
@@ -63,6 +63,8 @@ export function Portal(pro
el: (T extends true ? { readonly shadowRoot: ShadowRoot } : {}) &
(S extends true ? SVGGElement : HTMLDivElement)
) => void);
+ asElement?: keyof HTMLElementTagNameMap;
+ class?: string[];
children: JSX.Element;
}) {
const { useShadow } = props,
@@ -84,11 +86,13 @@ export function Portal(pro
createRoot(dispose => insert(el, () => (!clean() ? content!() : dispose()), null));
onCleanup(cleanup);
} else {
- const container = createElement(props.isSVG ? "g" : "div", props.isSVG),
- renderRoot =
- useShadow && container.attachShadow
- ? container.attachShadow({ mode: "open" })
- : container;
+ const container = createElement(props.isSVG ? "g" : props.asElement || "div", props.isSVG);
+ props.class && container.classList.add(...props.class.flatMap(str => str.split(" ")));
+
+ const renderRoot =
+ useShadow && container.attachShadow
+ ? container.attachShadow({ mode: "open" })
+ : container;
Object.defineProperty(container, "_$host", {
get() {
diff --git a/packages/solid/web/test/portal.spec.tsx b/packages/solid/web/test/portal.spec.tsx
index 9cae05b1..c47d5030 100644
--- a/packages/solid/web/test/portal.spec.tsx
+++ b/packages/solid/web/test/portal.spec.tsx
@@ -25,6 +25,56 @@ describe("Testing a simple Portal", () => {
});
});
+describe("Testing an Portal custom container", () => {
+ let div = document.createElement("div"),
+ disposer: () => void;
+ const testMount = document.createElement("div");
+ const Component = () => (
+
+ Hi
+
+ );
+
+ test("Create portal control flow", () => {
+ disposer = render(Component, div);
+ expect(div.innerHTML).toBe("");
+ const container = testMount.firstChild as HTMLElement & { _$host: HTMLElement };
+ expect(container.tagName).toBe("SECTION");
+ expect(container.innerHTML).toBe("Hi");
+ expect(container._$host).toBe(div);
+ });
+
+ test("dispose", () => {
+ disposer();
+ expect(div.innerHTML).toBe("");
+ });
+});
+
+describe('Testing Portal "class" property', () => {
+ let div = document.createElement("div"),
+ disposer: () => void;
+ const testMount = document.createElement("div");
+ const Component = () => (
+
+ ★
+
+ );
+
+ test("Create portal control flow", () => {
+ disposer = render(Component, div);
+ expect(div.innerHTML).toBe("");
+ const container = testMount.firstChild as HTMLElement & { _$host: HTMLElement };
+ expect(container.classList.toString()).toBe("flex flex-col text-gold bg-red");
+ expect(container.innerHTML).toBe("★");
+ expect(container._$host).toBe(div);
+ });
+
+ test("dispose", () => {
+ disposer();
+ expect(div.innerHTML).toBe("");
+ });
+});
+
describe("Testing an SVG Portal", () => {
let div = document.createElement("div"),
disposer: () => void;