diff --git a/cmd/wasm/main.go b/cmd/wasm/main.go
index 33a7eba..7ce280f 100644
--- a/cmd/wasm/main.go
+++ b/cmd/wasm/main.go
@@ -25,32 +25,19 @@ func renderToString(_ js.Value, args []js.Value) any {
if len(args) >= 2 && args[1].Type() == js.TypeString {
locale = args[1].String()
}
- ctx := html.NewContext(locale)
-
- layout := html.NewLayout(variant)
+ slots := make(map[string]html.Node)
if len(args) >= 3 && args[2].Type() == js.TypeObject {
- slots := args[2]
+ jsSlots := args[2]
for _, slot := range []string{"H", "L", "C", "R", "F"} {
- content := slots.Get(slot)
+ content := jsSlots.Get(slot)
if content.Type() == js.TypeString && content.String() != "" {
- switch slot {
- case "H":
- layout.H(html.Raw(content.String()))
- case "L":
- layout.L(html.Raw(content.String()))
- case "C":
- layout.C(html.Raw(content.String()))
- case "R":
- layout.R(html.Raw(content.String()))
- case "F":
- layout.F(html.Raw(content.String()))
- }
+ slots[slot] = html.Raw(content.String())
}
}
}
- return layout.Render(ctx)
+ return renderLayout(variant, locale, slots)
}
// registerComponents defines custom elements from the HLCRF slot map.
diff --git a/cmd/wasm/render_shared.go b/cmd/wasm/render_shared.go
new file mode 100644
index 0000000..42187e4
--- /dev/null
+++ b/cmd/wasm/render_shared.go
@@ -0,0 +1,35 @@
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package main
+
+import html "dappco.re/go/core/html"
+
+// renderLayout builds an HLCRF layout from slot nodes and renders it.
+// The helper is shared by the JS entrypoint and host-side tests so the
+// slot-to-layout mapping stays covered outside the wasm build.
+func renderLayout(variant, locale string, slots map[string]html.Node) string {
+ ctx := html.NewContext(locale)
+ layout := html.NewLayout(variant)
+
+ for _, slot := range canonicalSlotOrder {
+ node, ok := slots[slot]
+ if !ok || node == nil {
+ continue
+ }
+
+ switch slot {
+ case "H":
+ layout.H(node)
+ case "L":
+ layout.L(node)
+ case "C":
+ layout.C(node)
+ case "R":
+ layout.R(node)
+ case "F":
+ layout.F(node)
+ }
+ }
+
+ return layout.Render(ctx)
+}
diff --git a/cmd/wasm/render_shared_test.go b/cmd/wasm/render_shared_test.go
new file mode 100644
index 0000000..7288cbf
--- /dev/null
+++ b/cmd/wasm/render_shared_test.go
@@ -0,0 +1,49 @@
+//go:build !js
+
+// SPDX-Licence-Identifier: EUPL-1.2
+
+package main
+
+import (
+ "testing"
+
+ html "dappco.re/go/core/html"
+)
+
+func TestRenderLayout_RendersSlotsInVariantOrder(t *testing.T) {
+ got := renderLayout("HCF", "en-GB", map[string]html.Node{
+ "H": html.Raw("head"),
+ "C": html.Raw("body"),
+ "F": html.Raw("foot"),
+ })
+
+ want := `` +
+ `body` +
+ ``
+ if got != want {
+ t.Fatalf("renderLayout() = %q, want %q", got, want)
+ }
+}
+
+func TestRenderLayout_UsesLocaleAwareTextNodes(t *testing.T) {
+ got := renderLayout("C", "fr-FR", map[string]html.Node{
+ "C": html.El("p", html.Text("prompt.yes")),
+ })
+
+ want := `o
`
+ if got != want {
+ t.Fatalf("renderLayout() with locale = %q, want %q", got, want)
+ }
+}
+
+func TestRenderLayout_IgnoresMissingAndUnknownSlots(t *testing.T) {
+ got := renderLayout("C", "en-GB", map[string]html.Node{
+ "C": html.Raw("content"),
+ "X": html.Raw("ignored"),
+ })
+
+ want := `content`
+ if got != want {
+ t.Fatalf("renderLayout() with unknown slots = %q, want %q", got, want)
+ }
+}