Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ request to fix it.
- [lustre/component] Added a `on_context_change` config option to listen for changes in a parent's provided context.
- [lustre/element/svg] Add the `svg.namespace` constant.
- [lustre/element/svg] Add missing `svg.filter`, and `svg.view` elements.
- [lustre/runtime] Lustre is now more resilient against other scripts or browser plugins modifying the DOM.

### Changed

Expand All @@ -26,6 +27,8 @@ request to fix it.
- [lustre/component] Fixed a bug where a component's Shadow Root was incorrectly closed by default.
- [lustre/element] Fixed a bug where a top-level fragment would not be hydrated correctly.
- [lustre/element/keyed] Fixed a bug where keyed elements were not virtualised correctly.
- [lustre/event] Fixed a bug where debounced events of child elements would still fire after the node was removed.
- [lustre/event] Fixed a bug where events would not fire correctly after elements where added to or removed from a preceeding fragment.
- [lustre/server_component] Fixed a bug where empty `value` attributes would result in a value of `undefined`
- [lustre/server_component] Fixed a bug where events inside fragments would not work.

Expand Down

This file was deleted.

This file was deleted.

34 changes: 13 additions & 21 deletions src/lustre/dev/query.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,8 @@ fn find_in_children(
path: Path,
) -> Result(#(Element(msg), Path), Nil) {
case element {
Element(children:, ..) ->
Element(children:, ..) | Fragment(children:, ..) ->
find_in_list(children, query, path |> path.add(index, element.key), 0)
Fragment(children:, ..) -> find_in_list(children, query, path, index + 1)
UnsafeInnerHtml(..) -> Error(Nil)
Text(..) -> Error(Nil)
}
Expand All @@ -325,9 +324,6 @@ fn find_in_list(
case elements {
[] -> Error(Nil)

[Fragment(..) as first, ..rest] ->
find_in_list(list.append(first.children, rest), query, path, index + 1)

[first, ..rest] -> {
case find_path(in: first, matching: query, from: path, index:) {
Ok(element) -> Ok(element)
Expand All @@ -343,10 +339,8 @@ fn find_direct_child(
path: Path,
) -> Result(#(Element(msg), Path), Nil) {
case parent {
Element(children:, ..) -> find_matching_in_list(children, selector, path, 0)

Fragment(children:, ..) ->
find_matching_in_list(children, selector, path, 1)
Element(children:, ..) | Fragment(children:, ..) ->
find_matching_in_list(children, selector, path, 0)

UnsafeInnerHtml(..) | Text(..) -> Error(Nil)
}
Expand All @@ -365,8 +359,8 @@ fn find_matching_in_list(
find_matching_in_list(
list.append(first.children, rest),
selector,
path,
index + 1,
path.add(path, index, first.key),
0,
)

[first, ..rest] ->
Expand All @@ -386,12 +380,9 @@ fn find_descendant(
Ok(element) -> Ok(element)
Error(_) ->
case parent {
Element(children:, ..) ->
Element(children:, ..) | Fragment(children:, ..) ->
find_descendant_in_list(children, selector, path, 0)

Fragment(children:, ..) ->
find_descendant_in_list(children, selector, path, 1)

UnsafeInnerHtml(..) | Text(..) -> Error(Nil)
}
}
Expand Down Expand Up @@ -452,8 +443,8 @@ fn find_all_in_children(
query: Query,
) -> List(Element(msg)) {
case element {
Element(children:, ..) -> find_all_in_list(children, query)
Fragment(children:, ..) -> find_all_in_list(children, query)
Element(children:, ..) | Fragment(children:, ..) ->
find_all_in_list(children, query)
UnsafeInnerHtml(..) -> []
Text(..) -> []
}
Expand All @@ -479,8 +470,8 @@ fn find_all_direct_children(
selector: Selector,
) -> List(Element(msg)) {
case parent {
Element(children:, ..) -> find_all_matching_in_list(children, selector)
Fragment(children:, ..) -> find_all_matching_in_list(children, selector)
Element(children:, ..) | Fragment(children:, ..) ->
find_all_matching_in_list(children, selector)
UnsafeInnerHtml(..) | Text(..) -> []
}
}
Expand All @@ -505,8 +496,9 @@ fn find_all_descendants(
) -> List(Element(msg)) {
let direct_matches = find_all_direct_children(parent, selector)
let descendant_matches = case parent {
Element(children:, ..) -> find_all_descendants_in_list(children, selector)
Fragment(children:, ..) -> find_all_descendants_in_list(children, selector)
Element(children:, ..) | Fragment(children:, ..) ->
find_all_descendants_in_list(children, selector)

UnsafeInnerHtml(..) -> []
Text(..) -> []
}
Expand Down
10 changes: 0 additions & 10 deletions src/lustre/element.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,9 @@ pub fn fragment(children: List(Element(msg))) -> Element(msg) {
mapper: function.identity,
children:,
keyed_children: mutable_map.new(),
children_count: count_fragment_children(children, 0),
)
}

fn count_fragment_children(children: List(Element(msg)), count: Int) -> Int {
case children {
[child, ..rest] ->
count_fragment_children(rest, count + vnode.advance(child))

[] -> count
}
}

/// A function for constructing a wrapper element with custom raw HTML as its
/// content. Lustre will render the provided HTML verbatim, and will not touch
/// its children except when replacing the entire inner html on changes.
Expand Down
32 changes: 9 additions & 23 deletions src/lustre/element/keyed.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub fn element(
attributes: List(Attribute(msg)),
children: List(#(String, Element(msg))),
) -> Element(msg) {
let #(keyed_children, children, _) = extract_keyed_children(children)
let #(keyed_children, children) = extract_keyed_children(children)

vnode.element(
key: "",
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn namespaced(
attributes: List(Attribute(msg)),
children: List(#(String, Element(msg))),
) -> Element(msg) {
let #(keyed_children, children, _) = extract_keyed_children(children)
let #(keyed_children, children) = extract_keyed_children(children)

vnode.element(
key: "",
Expand All @@ -131,16 +131,9 @@ pub fn namespaced(
/// > use the same key in different lists.
///
pub fn fragment(children: List(#(String, Element(msg)))) -> Element(msg) {
let #(keyed_children, children, children_count) =
extract_keyed_children(children)
let #(keyed_children, children) = extract_keyed_children(children)

vnode.fragment(
key: "",
mapper: function.identity,
children:,
children_count:,
keyed_children:,
)
vnode.fragment(key: "", mapper: function.identity, children:, keyed_children:)
}

// ELEMENTS --------------------------------------------------------------------
Expand Down Expand Up @@ -184,23 +177,17 @@ pub fn dl(

fn extract_keyed_children(
children: List(#(String, Element(msg))),
) -> #(MutableMap(String, Element(msg)), List(Element(msg)), Int) {
do_extract_keyed_children(
children,
mutable_map.new(),
constants.empty_list,
0,
)
) -> #(MutableMap(String, Element(msg)), List(Element(msg))) {
do_extract_keyed_children(children, mutable_map.new(), constants.empty_list)
}

fn do_extract_keyed_children(
key_children_pairs: List(#(String, Element(msg))),
keyed_children: MutableMap(String, Element(msg)),
children: List(Element(msg)),
children_count: Int,
) -> #(MutableMap(String, Element(msg)), List(Element(msg)), Int) {
) -> #(MutableMap(String, Element(msg)), List(Element(msg))) {
case key_children_pairs {
[] -> #(keyed_children, list.reverse(children), children_count)
[] -> #(keyed_children, list.reverse(children))

[#(key, element), ..rest] -> {
let keyed_element = vnode.to_keyed(key, element)
Expand All @@ -212,9 +199,8 @@ fn do_extract_keyed_children(
_ -> mutable_map.insert(keyed_children, key, keyed_element)
}
let children = [keyed_element, ..children]
let children_count = children_count + vnode.advance(keyed_element)

do_extract_keyed_children(rest, keyed_children, children, children_count)
do_extract_keyed_children(rest, keyed_children, children)
}
}
}
1 change: 0 additions & 1 deletion src/lustre/runtime/client/component.ffi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ export const make_component = ({ init, update, view, config }, name) => {
}

this.#adoptedStyleNodes = await adoptStylesheets(this.#shadowRoot);
this.#runtime.offset = this.#adoptedStyleNodes.length;
}
};

Expand Down
4 changes: 0 additions & 4 deletions src/lustre/runtime/client/runtime.ffi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ export class Runtime {

root = null;

set offset(offset) {
this.#reconciler.offset = offset;
}

dispatch(msg, immediate = false) {
this.#shouldFlush ||= immediate;

Expand Down
13 changes: 2 additions & 11 deletions src/lustre/runtime/client/server_component.ffi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@
// used as the entry module when running esbuild so we *cant* use imports relative
// to src/.

import {
initialiseMetadata,
Reconciler,
} from "../../../../build/dev/javascript/lustre/lustre/vdom/reconciler.ffi.mjs";
import {
ContextRequestEvent,
adoptStylesheets,
} from "../../../../build/dev/javascript/lustre/lustre/runtime/client/runtime.ffi.mjs";
import { Reconciler } from "../../../../build/dev/javascript/lustre/lustre/vdom/reconciler.ffi.mjs";
import { adoptStylesheets, ContextRequestEvent } from "../../../../build/dev/javascript/lustre/lustre/runtime/client/runtime.ffi.mjs";
import {
mount_kind,
reconcile_kind,
Expand Down Expand Up @@ -123,8 +117,6 @@ export class ServerComponent extends HTMLElement {
mode: data.open_shadow_root ? "open" : "closed",
});

initialiseMetadata(null, this.#shadowRoot, "");

while (this.#shadowRoot.firstChild) {
this.#shadowRoot.firstChild.remove();
}
Expand Down Expand Up @@ -352,7 +344,6 @@ export class ServerComponent extends HTMLElement {
}

this.#adoptedStyleNodes = await adoptStylesheets(this.#shadowRoot);
this.#reconciler.offset = this.#adoptedStyleNodes.length;
}
}

Expand Down
Loading