Skip to content

Commit 0475ac2

Browse files
committed
improve <Portal/> container, add 2 new properties
- `asElement` allows to change Portal container element type - `class` allows to set class for Portal container
1 parent 3d3207d commit 0475ac2

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

packages/solid/web/src/index.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ export function Portal<T extends boolean = false, S extends boolean = false>(pro
6363
el: (T extends true ? { readonly shadowRoot: ShadowRoot } : {}) &
6464
(S extends true ? SVGGElement : HTMLDivElement)
6565
) => void);
66+
asElement?: keyof HTMLElementTagNameMap;
67+
class?: string[];
6668
children: JSX.Element;
6769
}) {
6870
const { useShadow } = props,
@@ -84,11 +86,13 @@ export function Portal<T extends boolean = false, S extends boolean = false>(pro
8486
createRoot(dispose => insert(el, () => (!clean() ? content!() : dispose()), null));
8587
onCleanup(cleanup);
8688
} else {
87-
const container = createElement(props.isSVG ? "g" : "div", props.isSVG),
88-
renderRoot =
89-
useShadow && container.attachShadow
90-
? container.attachShadow({ mode: "open" })
91-
: container;
89+
const container = createElement(props.isSVG ? "g" : props.asElement || "div", props.isSVG);
90+
props.class && container.classList.add(...props.class.flatMap(str => str.split(" ")));
91+
92+
const renderRoot =
93+
useShadow && container.attachShadow
94+
? container.attachShadow({ mode: "open" })
95+
: container;
9296

9397
Object.defineProperty(container, "_$host", {
9498
get() {

packages/solid/web/test/portal.spec.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,56 @@ describe("Testing a simple Portal", () => {
2525
});
2626
});
2727

28+
describe("Testing an Portal custom container", () => {
29+
let div = document.createElement("div"),
30+
disposer: () => void;
31+
const testMount = document.createElement("div");
32+
const Component = () => (
33+
<Portal mount={testMount} asElement="section">
34+
Hi
35+
</Portal>
36+
);
37+
38+
test("Create portal control flow", () => {
39+
disposer = render(Component, div);
40+
expect(div.innerHTML).toBe("");
41+
const container = testMount.firstChild as HTMLElement & { _$host: HTMLElement };
42+
expect(container.tagName).toBe("SECTION");
43+
expect(container.innerHTML).toBe("Hi");
44+
expect(container._$host).toBe(div);
45+
});
46+
47+
test("dispose", () => {
48+
disposer();
49+
expect(div.innerHTML).toBe("");
50+
});
51+
});
52+
53+
describe('Testing Portal "class" property', () => {
54+
let div = document.createElement("div"),
55+
disposer: () => void;
56+
const testMount = document.createElement("div");
57+
const Component = () => (
58+
<Portal mount={testMount} class={["flex flex-col", "text-gold bg-red"]}>
59+
60+
</Portal>
61+
);
62+
63+
test("Create portal control flow", () => {
64+
disposer = render(Component, div);
65+
expect(div.innerHTML).toBe("");
66+
const container = testMount.firstChild as HTMLElement & { _$host: HTMLElement };
67+
expect(container.classList.toString()).toBe("flex flex-col text-gold bg-red");
68+
expect(container.innerHTML).toBe("★");
69+
expect(container._$host).toBe(div);
70+
});
71+
72+
test("dispose", () => {
73+
disposer();
74+
expect(div.innerHTML).toBe("");
75+
});
76+
});
77+
2878
describe("Testing an SVG Portal", () => {
2979
let div = document.createElement("div"),
3080
disposer: () => void;

0 commit comments

Comments
 (0)