diff --git a/packages/solid/web/src/client.ts b/packages/solid/web/src/client.ts index 0cf6bbffe..c47f96258 100644 --- a/packages/solid/web/src/client.ts +++ b/packages/solid/web/src/client.ts @@ -1 +1,18 @@ export * from "dom-expressions/src/client.js"; +import { spread as baseSpread } from "dom-expressions/src/client.js"; + +const childPropNames = ["children", "innerHTML", "textContent", "innerText"]; + +export function spread( + node: Element, + props: Record = {}, + isSVG?: boolean, + skipChildren?: boolean +) { + return baseSpread( + node, + props, + isSVG, + skipChildren || !childPropNames.some(prop => prop in props) + ); +} diff --git a/packages/solid/web/test/element.spec.tsx b/packages/solid/web/test/element.spec.tsx index da36698d1..b250a0462 100644 --- a/packages/solid/web/test/element.spec.tsx +++ b/packages/solid/web/test/element.spec.tsx @@ -3,7 +3,15 @@ * @vitest-environment jsdom */ import { describe, expect, test } from "vitest"; -import { createRoot, createSignal, createUniqueId, JSX, children } from "../../src/index.js"; +import { + createMemo, + createRoot, + createSignal, + createUniqueId, + JSX, + children +} from "../../src/index.js"; +import { hydrate } from "../src/index.js"; declare module "solid-js/jsx-runtime" { namespace JSX { @@ -33,6 +41,39 @@ describe("Basic element attributes", () => { expect(d.innerHTML).toBe("

Hi

"); }); + test("hydrated innerHTML survives attribute-only spread updates", () => { + const root = document.createElement("main"); + root.innerHTML = `
Hello world!
`; + document.body.appendChild(root); + (globalThis as any)._$HY = { done: false, events: [], completed: new Set(), r: {} }; + + let div!: HTMLDivElement, setCount!: (value: number) => void; + + try { + const dispose = hydrate(() => { + const [count, set] = createSignal(0); + const data = createMemo(() => ({ + "data-whatever": count() === 1 ? "yes" : "no" + })); + setCount = set; + return ( +
+ ); + }, root); + + expect(div.textContent).toBe("Hello world!"); + setCount(1); + expect(div.textContent).toBe("Hello world!"); + expect(div.getAttribute("data-whatever")).toBe("yes"); + expect(div.getAttribute("class")).toBe("flex"); + expect(div.getAttribute("style")).toBe("color: red;"); + dispose(); + } finally { + root.remove(); + delete (globalThis as any)._$HY; + } + }); + test("classList", () => { const classes = { first: true, second: false, "third fourth": true }, d = (
) as HTMLDivElement;