fable-compiler / Fable.Lit

Write Fable Elmish apps with Lit
https://fable.io/Fable.Lit/
MIT License
91 stars 13 forks source link

Self closing tag LitComponents are not closing properly if there's an HTML element after it #48

Closed leolorenzoluis closed 2 years ago

leolorenzoluis commented 2 years ago

Given the following code:


let createBar index value =
    printfn "%A %A" index value
    let ratio = 240 / 10
    html $"""
            <rect 
              fill="red"
              x={( 320 / 10 )  * index}
              y={240 - ( value * ratio )}
              width={320 / 10}
              height="{value * ratio}"/>
        """

[<LitElement("ping-bar")>]
let chart () =

    // This call is obligatory to initialize the web component
    let _, props =
        LitElement.init(fun init ->
            init.props <- {| initial = Prop.Of(defaultValue = 0) |})
    html $"""
    <svg width="320" height="240">
      {
       seq { 1..11 } |> Seq.mapi(createBar)
      }
      {(createBar 5 6)}
      <rect fill="red" x="240" y="97" width="32" height="264"/>
    </svg>
    """

[<HookComponent>]
let Page() =
    let model, dispatch = Hook.useElmish(init, update)
    let renderItem (item: Monitor) =
        match model.Edit with
        | Some value when value.Id = item.Id->
            html $"""
            <div>
                <p>{item.Id}</p>
                <input value={item.FriendlyName} @keyup={EvVal (fun e -> UpdateFriendlyName e |> dispatch)}/>
                <input value={item.URL}/>
                <sl-button @click={Ev (fun e -> SaveMonitor model.Edit.Value |> dispatch)}>Save monitor</sl-button>
            </div>
            """
        | _ ->
            Monitor item dispatch

    html $"""
     <sl-button @click={Ev (fun e ->
            let newMonitor = {
                Id = Random().Next()
                FriendlyName = "Test1"
                URL = "2"
                Retries = 100
                HeartBeatInterval = 100
            }
            CreateMonitor newMonitor |> dispatch)}>New monitor</sl-button>
        <ping-bar/>
        {model.Monitors |> Lit.mapUnique (fun t -> t.Id.ToString()) renderItem}
    """

The {model.Monitors |> Lit.mapUnique (fun t -> t.Id.ToString()) renderItem} is getting rendered inside the <ping-bar> instead of closing the tag on itself.

Solution: Changing <ping-bar/> to <ping-bar></ping-bar> fixes it.

alfonsogarciacaro commented 2 years ago

Lit templates are just HTML and apparently self-closing tags are not allowed in custom web components in HTML either: https://github.com/lit/lit/issues/630

I assume that self-closing tags are allowed in React because JSX is not the same as HTML and they just get desugared to a component call without children.

leolorenzoluis commented 2 years ago

Got it. Was confused with the documentation

// MyComponent.fs
let register() = ()
[<LitElement("my-component")>]
let MyComponent() = ...
// App.fs
MyComponent.register()
html $"<my-component />"

Let me submit a PR to fix that