Closed JScearcy closed 5 months ago
This should be ok for review - going to bring up a discussion about testing to validate all behavior for any changes
Could we add some snapshot tests to this to check the static HTML rendering. It's about the only thing we have tests for so we may as well keep that up.
I added two new snapshot tests - one smoke test for patch, and a render which should validate that a fragments children are rendered in the correct order
Oh heck yeah, let's get this thing in! Thank you so much for this work, it's going to be really valuable. 💕
Address or start to address #16 Add client support for fragments in vdom
View used for testing
#### This is just extending the view from the counter ``` // VIEW ------------------------------------------------------------------------ fn count_fragment(count: Int) { let count_1 = int.to_string(count + 1) let count_2 = int.to_string(count + 2) let count_3 = int.to_string(count + 3) element.fragment([ html.p([], [element.text(count_1)]), html.p([], [element.text(count_2)]), html.p([], [element.text(count_3)]), ]) } fn text_fragment(count: String) { element.fragment([ html.p([], [element.text("text fragment 1")]), html.p([], [element.text("text fragment 2")]), html.p([], [element.text("text fragment 3")]), html.div([], [ html.p([], [element.text("skip nested fragment")]), element.fragment([ html.p([], [element.text("skip nested fragment"), element.text(count)]), html.p([], [element.text("skip nested fragment 2")]), html.p([], [element.text("skip nested fragment 3")]), ]), ]), ]) } fn view(model: Model) -> Element(Msg) { let styles = [#("width", "100vw"), #("height", "100vh"), #("padding", "1rem")] let count = int.to_string(model) element.fragment([ element.fragment([]), ui.centre( [attribute.style(styles)], ui.stack([], [ element.fragment([count_fragment(model), text_fragment(count)]), element.fragment([ ui.button([event.on_click(Incr)], [element.text("+")]), ]), html.p([attribute.style([#("text-align", "center")])], [ element.text(count), ]), element.fragment([html.p([], [element.text("Fragment text")])]), html.p([attribute.style([])], [element.text(count)]), ]), ), element.fragment([]), html.div([], [html.p([], [element.text("top level fragment second child")])]), element.fragment([ html.div([], [ html.p([], [ element.text("top level fragment nested fragment second child"), ]), ]), ]), element.fragment([]), ]) } ```Output of view used for testing (after incrementing)
```26
27
28
text fragment 1
text fragment 2
text fragment 3
skip nested fragment
skip nested fragment25
skip nested fragment 2
skip nested fragment 3
25
Fragment text
25
top level fragment second child
top level fragment nested fragment second child
View used for testing
#### This is just extending the view from the counter with keys ``` // VIEW ------------------------------------------------------------------------ type Person { Person(name: String) } fn person_li() -> Element(msg) { let person_list = [ Person("Test Person"), Person("Person Test"), Person("Person Person"), ] let person_lis = list.map(person_list, fn(person) { case person { Person(name) -> html.li([], [element.text("Person: "), element.text(name)]) } }) element.fragment(person_lis) } fn key_list() -> List(#(String, String)) { [ #("daf8235a-e7f3-4ce2-86aa-6eb1c41f12de", "first keyed"), #("12fbb6c3-ab8c-48db-90ce-e0119dc60f9e", "second keyed"), #("79f4ef78-c2f9-4ffa-9b57-1144639933c2", "third keyed"), ] } fn fragment_key_list() -> List(#(String, String)) { [ #("73f77eac-2495-4a05-90e9-fd0d68fc4891", "first fragment keyed"), #("da50a19f-a22e-4b51-bdba-2274f32127c1", "second fragment keyed"), #("03ce7794-ecee-40c2-9d2f-4366997cd0d1", "third fragment keyed"), ] } fn fragment_key_list_second() -> List(#(String, String)) { [ #("73f77eac-2495-4a05-90e9-fd0d68fc4892", "first second fragment keyed"), #("da50a19f-a22e-4b51-bdba-2274f32127c2", "second second fragment keyed"), #("03ce7794-ecee-40c2-9d2f-4366997cd0d2", "third second fragment keyed"), ] } fn keyed_nodes() { let key_list_tuple = list.map(key_list(), fn(val) { let #(key, label) = val #(key, html.li([], [element.text(label)])) }) element.keyed(html.ul([], _), key_list_tuple) } fn fragment_keyed_nodes() { let key_list_tuple = list.map(fragment_key_list(), fn(val) { let #(key, label) = val let element = html.li([], [element.text(label)]) #(key, element) }) element.keyed(element.fragment, key_list_tuple) } fn fragment_second_keyed_nodes() { let key_list_tuple = list.map(fragment_key_list_second(), fn(val) { let #(key, label) = val let element = html.li([], [element.text(label)]) #(key, element) }) element.keyed(element.fragment, key_list_tuple) } fn view(model: Model) -> Element(Msg) { let styles = [#("width", "100vw"), #("height", "100vh"), #("padding", "1rem")] let count = int.to_string(model) element.fragment([ ui.centre( [attribute.style(styles)], ui.stack([], [ keyed_nodes(), html.p([], [element.text("------")]), element.keyed(html.ul([], _), [ #("a", fragment_keyed_nodes()), #("b", html.li([], [element.text("fragment key sibling b")])), #("c", html.li([], [element.text("fragment key sibling c")])), #("d", fragment_second_keyed_nodes()), #("e", person_li()), ]), ui.button([event.on_click(Incr)], [element.text("+")]), html.p([attribute.style([#("text-align", "center")])], [ element.text(count), ]), html.p([attribute.style([])], [element.text(count)]), ]), ), html.div([], [html.p([], [element.text("top level fragment second child")])]), element.fragment([ html.div([], [ html.p([], [ element.text("top level fragment nested fragment second child"), ]), ]), ]), ]) } ```Output of view used for testing (after incrementing)
```------
35
35
top level fragment second child
top level fragment nested fragment second child