//go:build js && wasm package main import ( "syscall/js" html "forge.lthn.ai/core/go-html" ) // renderToString builds an HLCRF layout from JS arguments and returns HTML. // Slot content is injected via Raw() — the caller is responsible for sanitisation. // This is intentional: the WASM module is a rendering engine for trusted content // produced server-side or by the application's own templates. func renderToString(_ js.Value, args []js.Value) any { if len(args) < 1 { return "" } variant := args[0].String() ctx := html.NewContext() if len(args) >= 2 { ctx.Locale = args[1].String() } layout := html.NewLayout(variant) if len(args) >= 3 && args[2].Type() == js.TypeObject { slots := args[2] for _, slot := range []string{"H", "L", "C", "R", "F"} { content := slots.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())) } } } } return layout.Render(ctx) } // registerComponentsJS wraps buildComponentJS for the WASM→JS bridge. // Takes a JSON string of slot assignments, generates the WC bundle, // and executes it in the browser via the Function constructor. func registerComponentsJS(_ js.Value, args []js.Value) any { if len(args) < 1 { return js.ValueOf("error: slotsJSON argument required") } jsCode, err := buildComponentJS(args[0].String()) if err != nil { return js.ValueOf("error: " + err.Error()) } // Execute the generated WC definitions in the browser context. // Uses the standard Function constructor — the normal Go WASM→JS pattern. fn := js.Global().Call("Function", jsCode) fn.Invoke() return js.ValueOf(jsCode) } func main() { js.Global().Set("gohtml", js.ValueOf(map[string]any{ "renderToString": js.FuncOf(renderToString), "registerComponents": js.FuncOf(registerComponentsJS), })) select {} }