diff --git a/cmd/wasm/components.go b/cmd/wasm/components.go index faab087..f9f5673 100644 --- a/cmd/wasm/components.go +++ b/cmd/wasm/components.go @@ -63,7 +63,7 @@ func customElementClassSource(tag, slot string) string { "#shadow;" + "constructor(){super();this.#shadow=this.attachShadow({mode:\"closed\"});}" + "connectedCallback(){this.#shadow.textContent=\"\";const slot=this.getAttribute(\"data-slot\")||" + jsStringLiteral(slot) + ";" + - "this.dispatchEvent(new CustomEvent(\"wc-ready\",{detail:{tag:" + jsStringLiteral(tag) + ",slot}}));}" + + "this.dispatchEvent(new CustomEvent(\"wc-ready\",{detail:{tag:" + jsStringLiteral(tag) + ",slot},bubbles:true,composed:true}));}" + "render(html){const tpl=document.createElement(\"template\");tpl.insertAdjacentHTML(\"afterbegin\",html);" + "this.#shadow.textContent=\"\";this.#shadow.appendChild(tpl.content.cloneNode(true));}" + "}" diff --git a/cmd/wasm/register_test.go b/cmd/wasm/register_test.go index eaf57e0..313aa54 100644 --- a/cmd/wasm/register_test.go +++ b/cmd/wasm/register_test.go @@ -68,6 +68,8 @@ func TestCustomElementClassSource(t *testing.T) { assert.Contains(t, src, `#shadow`) assert.Contains(t, src, `data-slot`) assert.Contains(t, src, `wc-ready`) + assert.Contains(t, src, `bubbles:true`) + assert.Contains(t, src, `composed:true`) assert.Contains(t, src, `nav-bar`) assert.Contains(t, src, `H`) } diff --git a/codegen/codegen.go b/codegen/codegen.go index de446fd..229276b 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -45,7 +45,7 @@ var wcTemplate = template.Must(template.New("wc").Parse(`class {{.ClassName}} ex connectedCallback() { this.#shadow.textContent = ""; const slot = this.getAttribute("data-slot") || "{{.Slot}}"; - this.dispatchEvent(new CustomEvent("wc-ready", { detail: { tag: "{{.Tag}}", slot } })); + this.dispatchEvent(new CustomEvent("wc-ready", { detail: { tag: "{{.Tag}}", slot }, bubbles: true, composed: true })); } render(html) { const tpl = document.createElement("template"); diff --git a/codegen/codegen_test.go b/codegen/codegen_test.go index 56dc10c..36df710 100644 --- a/codegen/codegen_test.go +++ b/codegen/codegen_test.go @@ -14,6 +14,8 @@ func TestGenerateClass_Good(t *testing.T) { assert.Contains(t, js, "class PhotoGrid extends HTMLElement") assert.Contains(t, js, "attachShadow") assert.Contains(t, js, `mode: "closed"`) + assert.Contains(t, js, `bubbles: true`) + assert.Contains(t, js, `composed: true`) assert.Contains(t, js, "photo-grid") } diff --git a/docs/architecture.md b/docs/architecture.md index ed7551c..a1d5b1f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -271,7 +271,7 @@ gohtml.registerComponents(slots) Slot content is injected via `Raw()`. The caller is responsible for sanitisation -- the WASM module is a rendering engine for trusted content produced server-side or by the application's own templates. -`registerComponents(slots)` accepts the same slot-map shape used by the codegen CLI and registers closed-shadow custom elements in the browser at runtime. It skips invalid or duplicate tags and mirrors the generated component lifecycle by dispatching a `wc-ready` event when each element connects. +`registerComponents(slots)` accepts the same slot-map shape used by the codegen CLI and registers closed-shadow custom elements in the browser at runtime. It skips invalid or duplicate tags and mirrors the generated component lifecycle by dispatching a bubbling, composed `wc-ready` event when each element connects. ### Size Budget @@ -307,7 +307,7 @@ The `codegen` package (`codegen/codegen.go`) generates ES2022 class definitions 1. A class extending `HTMLElement` with a private `#shadow` field. 2. `constructor()` attaching a closed shadow root (`mode: "closed"`). -3. `connectedCallback()` dispatching a `wc-ready` custom event with the tag name and slot. +3. `connectedCallback()` dispatching a bubbling, composed `wc-ready` custom event with the tag name and slot. 4. `render(html)` method that sets shadow content from a `