Packages
lustre
5.3.2
5.7.1
5.7.0
5.6.0
5.5.2
5.5.1
5.5.0
5.4.0
5.3.5
5.3.4
5.3.3
5.3.2
5.3.1
5.3.0
5.2.1
5.2.0
5.1.1
5.1.0
5.0.3
5.0.2
5.0.1
5.0.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.8
4.1.7
4.1.6
4.1.5
4.1.4
4.1.3
4.1.2
4.1.1
4.1.0
4.0.0
4.0.0-rc1
4.0.0-rc.2
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.12
3.0.11
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.5
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.2
3.0.0-rc.1
2.0.1
2.0.0
1.3.0
1.2.0
1.1.0
1.0.0
Create HTML templates, single page applications, Web Components, and real-time server components in Gleam!
Current section
Files
Jump to
Current section
Files
src/lustre@dev@query.erl
-module(lustre@dev@query).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/lustre/dev/query.gleam").
-export([element/1, child/2, descendant/2, 'and'/2, tag/1, namespaced/2, attribute/2, class/1, style/2, id/1, data/2, test_id/1, aria/2, text/1, matches/2, to_readable_string/1, find_all/2, find_path/4, find/2, has/2]).
-export_type(['query'/0, selector/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque 'query'() :: {find_element, selector()} |
{find_child, 'query'(), selector()} |
{find_descendant, 'query'(), selector()}.
-opaque selector() :: {all, list(selector())} |
{type, binary(), binary()} |
{has_attribute, binary(), binary()} |
{has_class, binary()} |
{has_style, binary(), binary()} |
{contains, binary()}.
-file("src/lustre/dev/query.gleam", 41).
?DOC(" Find any elements in a view that match the given [`Selector`](#Selector).\n").
-spec element(selector()) -> 'query'().
element(Selector) ->
{find_element, Selector}.
-file("src/lustre/dev/query.gleam", 49).
?DOC(
" Given a `Query` that finds an element, find any of that element's _direct_\n"
" children that match the given [`Selector`](#Selector). This is similar to the\n"
" CSS `>` combinator.\n"
).
-spec child('query'(), selector()) -> 'query'().
child(Parent, Selector) ->
{find_child, Parent, Selector}.
-file("src/lustre/dev/query.gleam", 57).
?DOC(
" Given a `Query` that finds an element, find any of that element's _descendants_\n"
" that match the given [`Selector`](#Selector). This will walk the entire tree\n"
" from the matching parent.\n"
).
-spec descendant('query'(), selector()) -> 'query'().
descendant(Parent, Selector) ->
{find_descendant, Parent, Selector}.
-file("src/lustre/dev/query.gleam", 95).
?DOC(
" Combine two selectors into one that must match both. For example, if you have\n"
" a selector for div elements and a selector for elements with the class \"wibble\"\n"
" then they can be combined into a selector that matches only div elements with\n"
" the class \"wibble\".\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" let div = query.tag(\"div\")\n"
" let wibble = query.class(\"wibble\")\n"
"\n"
" query.element(matching: div |> query.and(wibble))\n"
" }\n"
" ```\n"
"\n"
" You can chain multiple `and` calls together to combine many selectors into\n"
" something more specific.\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" query.tag(\"div\")\n"
" |> query.and(query.class(\"wibble\"))\n"
" |> query.and(query.data(\"open\", \"true\"))\n"
" }\n"
" ```\n"
"\n"
" > **Note**: if you find yourself crafting complex selectors, consider using\n"
" > a test id on the element(s) you want to find instead.\n"
).
-spec 'and'(selector(), selector()) -> selector().
'and'(First, Second) ->
case First of
{all, []} ->
{all, [Second]};
{all, Others} ->
{all, [Second | Others]};
_ ->
{all, [First, Second]}
end.
-file("src/lustre/dev/query.gleam", 107).
?DOC(
" Select elements based on their tag name, like `\"div\"`, `\"span\"`, or `\"a\"`.\n"
" To select elements with an XML namespace - such as SVG elements - use the\n"
" [`namespaced`](#namespaced) selector instead.\n"
).
-spec tag(binary()) -> selector().
tag(Value) ->
{type, <<""/utf8>>, Value}.
-file("src/lustre/dev/query.gleam", 125).
?DOC(
" Select elements based on their tag name and XML namespace. This is useful\n"
" for selecting SVG elements or other XML elements that have a namespace.\n"
" For example, to select an SVG circle element, you would use:\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" let svg = \"http://www.w3.org/2000/svg\"\n"
"\n"
" query.element(matching: query.namespaced(svg, \"circle\"))\n"
" }\n"
" ```\n"
).
-spec namespaced(binary(), binary()) -> selector().
namespaced(Namespace, Tag) ->
{type, Namespace, Tag}.
-file("src/lustre/dev/query.gleam", 154).
?DOC(
" Select elements that have the specified attribute with the given value. If\n"
" the value is left blank, this selector will match any element that has the\n"
" attribute, _regardless of its value_.\n"
"\n"
" For example, to select a form input with the name \"username\", you would\n"
" use:\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" query.element(matching: query.attribute(\"name\", \"username\"))\n"
" }\n"
" ```\n"
"\n"
" Or to select elements with the `disabled` attribute:\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" query.element(matching: query.attribute(\"disabled\", \"\"))\n"
" }\n"
" ```\n"
).
-spec attribute(binary(), binary()) -> selector().
attribute(Name, Value) ->
{has_attribute, Name, Value}.
-file("src/lustre/dev/query.gleam", 169).
?DOC(
" Select elements that include the given space-separated class name(s). For\n"
" example given the element `<div class=\"foo bar baz\">`, the following selectors\n"
" would match:\n"
"\n"
" - `query.class(\"foo\")`\n"
"\n"
" - `query.class(\"bar baz\")`\n"
"\n"
" If you need to match the class attribute exactly, you can use the [`attribute`](#attribute)\n"
" selector instead.\n"
).
-spec class(binary()) -> selector().
class(Name) ->
{has_class, Name}.
-file("src/lustre/dev/query.gleam", 177).
?DOC(
" Select elements that have the specified inline style with the given value.\n"
" If the value is left blank, this selector will match any element that has\n"
" the given style, _regardless of its value_.\n"
).
-spec style(binary(), binary()) -> selector().
style(Name, Value) ->
{has_style, Name, Value}.
-file("src/lustre/dev/query.gleam", 184).
?DOC(
" Select an element based on its `id` attribute. Well-formed HTML means that\n"
" only one element should have a given id.\n"
).
-spec id(binary()) -> selector().
id(Name) ->
{has_attribute, <<"id"/utf8>>, Name}.
-file("src/lustre/dev/query.gleam", 199).
?DOC(
" Select elements that have the given `data-*` attribute. For example you can\n"
" select a custom disclosure element that is currently open with:\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" query.element(matching: query.data(\"open\", \"true\"))\n"
" }\n"
" ```\n"
).
-spec data(binary(), binary()) -> selector().
data(Name, Value) ->
{has_attribute, <<"data-"/utf8, Name/binary>>, Value}.
-file("src/lustre/dev/query.gleam", 207).
?DOC(
" It is a common convention to use the `data-test-id` attribute to mark elements\n"
" for easy selection in tests. This function is a shorthand for writing\n"
" `query.data(\"test-id\", value)`\n"
).
-spec test_id(binary()) -> selector().
test_id(Value) ->
data(<<"test-id"/utf8>>, Value).
-file("src/lustre/dev/query.gleam", 222).
?DOC(
" Select elements that have the given `aria-*` attribute. For example you can\n"
" select the trigger of a dropdown menu with:\n"
"\n"
" ```gleam\n"
" import lustre/dev/query\n"
"\n"
" pub fn example() {\n"
" query.element(matching: query.aria(\"expanded\", \"true\"))\n"
" }\n"
" ```\n"
).
-spec aria(binary(), binary()) -> selector().
aria(Name, Value) ->
{has_attribute, <<"aria-"/utf8, Name/binary>>, Value}.
-file("src/lustre/dev/query.gleam", 254).
?DOC(
" Select elements whose text content matches the given string exactly. This\n"
" includes text from **inline** children, but not from **block** children. For\n"
" example, given the following HTML:\n"
"\n"
" ```html\n"
" <p>Hello, <span class=\"font-bold\">Joe</span>!</p>\n"
" ```\n"
"\n"
" The selector `query.text(\"Hello, Joe!\")` would match the `<p>` element because\n"
" the text content of the inline `<span>` element is included in the paragraph's\n"
" text content.\n"
"\n"
" Whitespace must match exactly, so the selector `query.text(\"Hello, Joe!\")`\n"
" would not match an element like:\n"
"\n"
" ```gleam\n"
" html.p([], [html.text(\"Hello, Joe!\")])\n"
" ```\n"
"\n"
" > **Note**: while this selector makes a best-effort attempt to include the\n"
" > text content of inline children, this cannot account for block elements that\n"
" > are styled as inline by CSS stylesheets.\n"
"\n"
" > **Note**: often it is better to use more precise selectors such as\n"
" > [`id`](#id), [`class`](#class), or [`test_id`](#test_id). You should reach\n"
" > for this selector only when you want to assert that an element contains\n"
" > some specific text, such as in a hero banner or a copyright notice.\n"
).
-spec text(binary()) -> selector().
text(Content) ->
{contains, Content}.
-file("src/lustre/dev/query.gleam", 610).
-spec text_content(lustre@vdom@vnode:element(any()), boolean(), binary()) -> binary().
text_content(Element, Inline, Content) ->
case Element of
{fragment, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(5, Element),
Content,
fun(Content@1, Child) ->
text_content(Child, true, Content@1)
end
);
{element, _, _, _, _, _, _, _, _, _, _} when not Inline orelse (erlang:element(
5,
Element
) =/= <<""/utf8>>) ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@2, Child@1) ->
text_content(Child@1, true, Content@2)
end
);
{element, _, _, _, _, <<"a"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"abbr"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"acronym"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"b"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"bdo"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"big"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"br"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"button"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"cite"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"code"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"dfn"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"em"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"i"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"img"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"input"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"kbd"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"label"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"map"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"object"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"output"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"q"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"samp"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"script"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"select"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"small"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"span"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"strong"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"sub"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"sup"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"textarea"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"time"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"tt"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, <<"var"/utf8>>, _, _, _, _, _} ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@3, Child@2) ->
text_content(Child@2, true, Content@3)
end
);
{element, _, _, _, _, _, _, _, _, _, _} ->
Rule = <<"display:inline"/utf8>>,
Is_inline = gleam@list:any(
erlang:element(7, Element),
fun(Attribute) -> case Attribute of
{attribute, _, <<"style"/utf8>>, Value} ->
gleam_stdlib:contains_string(Value, Rule);
_ ->
false
end end
),
case Is_inline of
true ->
gleam@list:fold(
erlang:element(8, Element),
Content,
fun(Content@4, Child@3) ->
text_content(Child@3, true, Content@4)
end
);
false ->
Content
end;
{text, _, _, _, _} ->
<<Content/binary, (erlang:element(5, Element))/binary>>;
{unsafe_inner_html, _, _, _, _, _, _, _} ->
Content
end.
-file("src/lustre/dev/query.gleam", 536).
?DOC(" Check if the given target element matches the given [`Selector`](#Selector).\n").
-spec matches(lustre@vdom@vnode:element(any()), selector()) -> boolean().
matches(Element, Selector) ->
case {Element, Selector} of
{_, {all, Selectors}} ->
gleam@list:all(
Selectors,
fun(_capture) -> matches(Element, _capture) end
);
{{element, _, _, _, Namespace, Tag, _, _, _, _, _}, {type, _, _}} ->
(Namespace =:= erlang:element(2, Selector)) andalso (Tag =:= erlang:element(
3,
Selector
));
{{unsafe_inner_html, _, _, _, Namespace, Tag, _, _}, {type, _, _}} ->
(Namespace =:= erlang:element(2, Selector)) andalso (Tag =:= erlang:element(
3,
Selector
));
{{element, _, _, _, _, _, Attributes, _, _, _, _},
{has_attribute, Name, <<""/utf8>>}} ->
gleam@list:any(Attributes, fun(Attribute) -> case Attribute of
{attribute, _, _, _} ->
erlang:element(3, Attribute) =:= Name;
_ ->
false
end end);
{{unsafe_inner_html, _, _, _, _, _, Attributes, _},
{has_attribute, Name, <<""/utf8>>}} ->
gleam@list:any(Attributes, fun(Attribute) -> case Attribute of
{attribute, _, _, _} ->
erlang:element(3, Attribute) =:= Name;
_ ->
false
end end);
{{element, _, _, _, _, _, Attributes@1, _, _, _, _},
{has_attribute, Name@1, Value}} ->
gleam@list:contains(
Attributes@1,
lustre@attribute:attribute(Name@1, Value)
);
{{unsafe_inner_html, _, _, _, _, _, Attributes@1, _},
{has_attribute, Name@1, Value}} ->
gleam@list:contains(
Attributes@1,
lustre@attribute:attribute(Name@1, Value)
);
{{element, _, _, _, _, _, Attributes@2, _, _, _, _},
{has_class, Name@2}} ->
gleam@list:fold_until(
gleam@string:split(Name@2, <<" "/utf8>>),
true,
fun(_, Class) ->
Name@3 = gleam@string:trim_end(Class),
Matches = gleam@list:any(
Attributes@2,
fun(Attribute@1) -> case Attribute@1 of
{attribute, _, <<"class"/utf8>>, Value@1} ->
(((Value@1 =:= Name@3) orelse gleam_stdlib:string_starts_with(
Value@1,
<<Name@3/binary, " "/utf8>>
))
orelse gleam_stdlib:string_ends_with(
Value@1,
<<" "/utf8, Name@3/binary>>
))
orelse gleam_stdlib:contains_string(
Value@1,
<<<<" "/utf8, Name@3/binary>>/binary,
" "/utf8>>
);
_ ->
false
end end
),
case Matches of
true ->
{continue, true};
false ->
{stop, false}
end
end
);
{{unsafe_inner_html, _, _, _, _, _, Attributes@2, _},
{has_class, Name@2}} ->
gleam@list:fold_until(
gleam@string:split(Name@2, <<" "/utf8>>),
true,
fun(_, Class) ->
Name@3 = gleam@string:trim_end(Class),
Matches = gleam@list:any(
Attributes@2,
fun(Attribute@1) -> case Attribute@1 of
{attribute, _, <<"class"/utf8>>, Value@1} ->
(((Value@1 =:= Name@3) orelse gleam_stdlib:string_starts_with(
Value@1,
<<Name@3/binary, " "/utf8>>
))
orelse gleam_stdlib:string_ends_with(
Value@1,
<<" "/utf8, Name@3/binary>>
))
orelse gleam_stdlib:contains_string(
Value@1,
<<<<" "/utf8, Name@3/binary>>/binary,
" "/utf8>>
);
_ ->
false
end end
),
case Matches of
true ->
{continue, true};
false ->
{stop, false}
end
end
);
{{element, _, _, _, _, _, Attributes@3, _, _, _, _},
{has_style, Name@4, Value@2}} ->
Rule = <<<<<<Name@4/binary, ":"/utf8>>/binary, Value@2/binary>>/binary,
";"/utf8>>,
gleam@list:any(Attributes@3, fun(Attribute@2) -> case Attribute@2 of
{attribute, _, <<"style"/utf8>>, Value@3} ->
gleam_stdlib:contains_string(Value@3, Rule);
_ ->
false
end end);
{{unsafe_inner_html, _, _, _, _, _, Attributes@3, _},
{has_style, Name@4, Value@2}} ->
Rule = <<<<<<Name@4/binary, ":"/utf8>>/binary, Value@2/binary>>/binary,
";"/utf8>>,
gleam@list:any(Attributes@3, fun(Attribute@2) -> case Attribute@2 of
{attribute, _, <<"style"/utf8>>, Value@3} ->
gleam_stdlib:contains_string(Value@3, Rule);
_ ->
false
end end);
{{element, _, _, _, _, _, _, _, _, _, _}, {contains, Content}} ->
_pipe = Element,
_pipe@1 = text_content(_pipe, false, <<""/utf8>>),
gleam_stdlib:contains_string(_pipe@1, Content);
{_, _} ->
false
end.
-file("src/lustre/dev/query.gleam", 349).
-spec find_matching_in_list(
list(lustre@vdom@vnode:element(SWE)),
selector(),
lustre@vdom@path:path(),
integer()
) -> {ok, {lustre@vdom@vnode:element(SWE), lustre@vdom@path:path()}} |
{error, nil}.
find_matching_in_list(Elements, Selector, Path, Index) ->
case Elements of
[] ->
{error, nil};
[{fragment, _, _, _, _, _} = First | Rest] ->
find_matching_in_list(
lists:append(erlang:element(5, First), Rest),
Selector,
lustre@vdom@path:add(Path, Index, erlang:element(3, First)),
0
);
[First@1 | Rest@1] ->
case matches(First@1, Selector) of
true ->
{ok,
{First@1,
lustre@vdom@path:add(
Path,
Index,
erlang:element(3, First@1)
)}};
false ->
find_matching_in_list(Rest@1, Selector, Path, Index + 1)
end
end.
-file("src/lustre/dev/query.gleam", 336).
-spec find_direct_child(
lustre@vdom@vnode:element(SVZ),
selector(),
lustre@vdom@path:path()
) -> {ok, {lustre@vdom@vnode:element(SVZ), lustre@vdom@path:path()}} |
{error, nil}.
find_direct_child(Parent, Selector, Path) ->
case Parent of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_matching_in_list(Children, Selector, Path, 0);
{fragment, _, _, _, Children, _} ->
find_matching_in_list(Children, Selector, Path, 0);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
{error, nil};
{text, _, _, _, _} ->
{error, nil}
end.
-file("src/lustre/dev/query.gleam", 479).
-spec find_all_matching_in_list(
list(lustre@vdom@vnode:element(SXM)),
selector()
) -> list(lustre@vdom@vnode:element(SXM)).
find_all_matching_in_list(Elements, Selector) ->
case Elements of
[] ->
[];
[First | Rest] ->
case matches(First, Selector) of
true ->
[First | find_all_matching_in_list(Rest, Selector)];
false ->
find_all_matching_in_list(Rest, Selector)
end
end.
-file("src/lustre/dev/query.gleam", 468).
-spec find_all_direct_children(lustre@vdom@vnode:element(SXI), selector()) -> list(lustre@vdom@vnode:element(SXI)).
find_all_direct_children(Parent, Selector) ->
case Parent of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_all_matching_in_list(Children, Selector);
{fragment, _, _, _, Children, _} ->
find_all_matching_in_list(Children, Selector);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
[];
{text, _, _, _, _} ->
[]
end.
-file("src/lustre/dev/query.gleam", 745).
-spec sort_selectors(list(selector())) -> list(selector()).
sort_selectors(Selectors) ->
gleam@list:sort(
begin
gleam@list:flat_map(Selectors, fun(Selector) -> case Selector of
{all, Selectors@1} ->
Selectors@1;
_ ->
[Selector]
end end)
end,
fun(A, B) -> case {A, B} of
{{all, _}, _} ->
erlang:error(#{gleam_error => panic,
message => <<"`All` selectors should be flattened"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"lustre/dev/query"/utf8>>,
function => <<"sort_selectors"/utf8>>,
line => 756});
{_, {all, _}} ->
erlang:error(#{gleam_error => panic,
message => <<"`All` selectors should be flattened"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"lustre/dev/query"/utf8>>,
function => <<"sort_selectors"/utf8>>,
line => 756});
{{type, _, _}, {type, _, _}} ->
case gleam@string:compare(
erlang:element(2, A),
erlang:element(2, B)
) of
eq ->
gleam@string:compare(
erlang:element(3, A),
erlang:element(3, B)
);
Order ->
Order
end;
{{type, _, _}, _} ->
lt;
{_, {type, _, _}} ->
gt;
{{has_attribute, <<"id"/utf8>>, _},
{has_attribute, <<"id"/utf8>>, _}} ->
gleam@string:compare(
erlang:element(3, A),
erlang:element(3, B)
);
{{has_attribute, <<"id"/utf8>>, _}, _} ->
lt;
{_, {has_attribute, <<"id"/utf8>>, _}} ->
gt;
{{has_attribute, _, _}, {has_attribute, _, _}} ->
case gleam@string:compare(
erlang:element(2, A),
erlang:element(2, B)
) of
eq ->
gleam@string:compare(
erlang:element(3, A),
erlang:element(3, B)
);
Order@1 ->
Order@1
end;
{{has_attribute, _, _}, _} ->
lt;
{_, {has_attribute, _, _}} ->
gt;
{{has_style, _, _}, {has_style, _, _}} ->
gleam@string:compare(
erlang:element(2, A),
erlang:element(2, B)
);
{{has_style, _, _}, _} ->
lt;
{_, {has_style, _, _}} ->
gt;
{{has_class, _}, {has_class, _}} ->
gleam@string:compare(
erlang:element(2, A),
erlang:element(2, B)
);
{{has_class, _}, _} ->
lt;
{_, {has_class, _}} ->
gt;
{{contains, _}, {contains, _}} ->
gleam@string:compare(
erlang:element(2, A),
erlang:element(2, B)
)
end end
).
-file("src/lustre/dev/query.gleam", 718).
-spec selector_to_readable_string(selector()) -> binary().
selector_to_readable_string(Selector) ->
case Selector of
{all, []} ->
<<""/utf8>>;
{type, <<""/utf8>>, <<""/utf8>>} ->
<<""/utf8>>;
{has_attribute, <<""/utf8>>, _} ->
<<""/utf8>>;
{has_class, <<""/utf8>>} ->
<<""/utf8>>;
{has_style, <<""/utf8>>, _} ->
<<""/utf8>>;
{has_style, _, <<""/utf8>>} ->
<<""/utf8>>;
{contains, <<""/utf8>>} ->
<<""/utf8>>;
{all, Selectors} ->
_pipe = Selectors,
_pipe@1 = sort_selectors(_pipe),
_pipe@2 = gleam@list:map(_pipe@1, fun selector_to_readable_string/1),
erlang:list_to_binary(_pipe@2);
{type, <<""/utf8>>, Tag} ->
Tag;
{type, Namespace, Tag@1} ->
<<<<Namespace/binary, ":"/utf8>>/binary, Tag@1/binary>>;
{has_attribute, <<"id"/utf8>>, Value} ->
<<"#"/utf8, Value/binary>>;
{has_attribute, Name, <<""/utf8>>} ->
<<<<"["/utf8, Name/binary>>/binary, "]"/utf8>>;
{has_attribute, Name@1, Value@1} ->
<<<<<<<<"["/utf8, Name@1/binary>>/binary, "=\""/utf8>>/binary,
Value@1/binary>>/binary,
"\"]"/utf8>>;
{has_class, Name@2} ->
<<"."/utf8, Name@2/binary>>;
{has_style, Name@3, Value@2} ->
<<<<<<<<"[style*=\""/utf8, Name@3/binary>>/binary, ":"/utf8>>/binary,
Value@2/binary>>/binary,
"\"]"/utf8>>;
{contains, Content} ->
<<<<":contains(\""/utf8, Content/binary>>/binary, "\")"/utf8>>
end.
-file("src/lustre/dev/query.gleam", 704).
?DOC(
" Print a `Query` as a human-readable string similar to a CSS selector. This\n"
" function is primarily intended for debugging and testing purposes: for example,\n"
" you might use this to include the selector in a snapshot test for easier\n"
" review.\n"
"\n"
" > **Note**: while similar, this function is not guaranteed to produce a valid\n"
" > CSS selector. Specifically, queries that use the [`text`](#text) selector\n"
" > will not be valid CSS selectors as they use the `:contains` pseudo-class,\n"
" > which is not part of the CSS spec!\n"
).
-spec to_readable_string('query'()) -> binary().
to_readable_string(Query) ->
case Query of
{find_element, Selector} ->
selector_to_readable_string(Selector);
{find_child, Parent, Selector@1} ->
<<<<(to_readable_string(Parent))/binary, " > "/utf8>>/binary,
(selector_to_readable_string(Selector@1))/binary>>;
{find_descendant, Parent@1, Selector@2} ->
<<<<(to_readable_string(Parent@1))/binary, " "/utf8>>/binary,
(selector_to_readable_string(Selector@2))/binary>>
end.
-file("src/lustre/dev/query.gleam", 453).
-spec find_all_in_list(list(lustre@vdom@vnode:element(SXD)), 'query'()) -> list(lustre@vdom@vnode:element(SXD)).
find_all_in_list(Elements, Query) ->
case Elements of
[] ->
[];
[First | Rest] ->
First_matches = find_all(First, Query),
Rest_matches = find_all_in_list(Rest, Query),
lists:append(First_matches, Rest_matches)
end.
-file("src/lustre/dev/query.gleam", 418).
?DOC(
" Like [`find`](#find) but returns every element in the view that matches the\n"
" given query.\n"
).
-spec find_all(lustre@vdom@vnode:element(SWV), 'query'()) -> list(lustre@vdom@vnode:element(SWV)).
find_all(Root, Query) ->
case Query of
{find_element, Selector} ->
case matches(Root, Selector) of
true ->
[Root | find_all_in_children(Root, Query)];
false ->
find_all_in_children(Root, Query)
end;
{find_child, Parent, Selector@1} ->
_pipe = Root,
_pipe@1 = find_all(_pipe, Parent),
gleam@list:flat_map(
_pipe@1,
fun(_capture) ->
find_all_direct_children(_capture, Selector@1)
end
);
{find_descendant, Parent@1, Selector@2} ->
_pipe@2 = Root,
_pipe@3 = find_all(_pipe@2, Parent@1),
gleam@list:flat_map(
_pipe@3,
fun(_capture@1) ->
find_all_descendants(_capture@1, Selector@2)
end
)
end.
-file("src/lustre/dev/query.gleam", 441).
-spec find_all_in_children(lustre@vdom@vnode:element(SWZ), 'query'()) -> list(lustre@vdom@vnode:element(SWZ)).
find_all_in_children(Element, Query) ->
case Element of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_all_in_list(Children, Query);
{fragment, _, _, _, Children, _} ->
find_all_in_list(Children, Query);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
[];
{text, _, _, _, _} ->
[]
end.
-file("src/lustre/dev/query.gleam", 509).
-spec find_all_descendants_in_list(
list(lustre@vdom@vnode:element(SXV)),
selector()
) -> list(lustre@vdom@vnode:element(SXV)).
find_all_descendants_in_list(Elements, Selector) ->
case Elements of
[] ->
[];
[First | Rest] ->
First_matches = find_all_descendants(First, Selector),
Rest_matches = find_all_descendants_in_list(Rest, Selector),
lists:append(First_matches, Rest_matches)
end.
-file("src/lustre/dev/query.gleam", 493).
-spec find_all_descendants(lustre@vdom@vnode:element(SXR), selector()) -> list(lustre@vdom@vnode:element(SXR)).
find_all_descendants(Parent, Selector) ->
Direct_matches = find_all_direct_children(Parent, Selector),
Descendant_matches = case Parent of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_all_descendants_in_list(Children, Selector);
{fragment, _, _, _, Children, _} ->
find_all_descendants_in_list(Children, Selector);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
[];
{text, _, _, _, _} ->
[]
end,
lists:append(Direct_matches, Descendant_matches).
-file("src/lustre/dev/query.gleam", 318).
-spec find_in_list(
list(lustre@vdom@vnode:element(SVT)),
'query'(),
lustre@vdom@path:path(),
integer()
) -> {ok, {lustre@vdom@vnode:element(SVT), lustre@vdom@path:path()}} |
{error, nil}.
find_in_list(Elements, Query, Path, Index) ->
case Elements of
[] ->
{error, nil};
[First | Rest] ->
case find_path(First, Query, Index, Path) of
{ok, Element} ->
{ok, Element};
{error, _} ->
find_in_list(Rest, Query, Path, Index + 1)
end
end.
-file("src/lustre/dev/query.gleam", 277).
?DOC(false).
-spec find_path(
lustre@vdom@vnode:element(SVJ),
'query'(),
integer(),
lustre@vdom@path:path()
) -> {ok, {lustre@vdom@vnode:element(SVJ), lustre@vdom@path:path()}} |
{error, nil}.
find_path(Root, Query, Index, Path) ->
case Query of
{find_element, Selector} ->
case matches(Root, Selector) of
true ->
{ok,
{Root,
begin
_pipe = Path,
lustre@vdom@path:add(
_pipe,
Index,
erlang:element(3, Root)
)
end}};
false ->
find_in_children(Root, Query, Index, Path)
end;
{find_child, Parent, Selector@1} ->
case find_path(Root, Parent, Index, Path) of
{ok, {Element, Path@1}} ->
find_direct_child(Element, Selector@1, Path@1);
{error, _} ->
{error, nil}
end;
{find_descendant, Parent@1, Selector@2} ->
case find_path(Root, Parent@1, Index, Path) of
{ok, {Element@1, Path@2}} ->
find_descendant(Element@1, Selector@2, Path@2);
{error, _} ->
{error, nil}
end
end.
-file("src/lustre/dev/query.gleam", 304).
-spec find_in_children(
lustre@vdom@vnode:element(SVO),
'query'(),
integer(),
lustre@vdom@path:path()
) -> {ok, {lustre@vdom@vnode:element(SVO), lustre@vdom@path:path()}} |
{error, nil}.
find_in_children(Element, Query, Index, Path) ->
case Element of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_in_list(
Children,
Query,
begin
_pipe = Path,
lustre@vdom@path:add(
_pipe,
Index,
erlang:element(3, Element)
)
end,
0
);
{fragment, _, _, _, Children, _} ->
find_in_list(
Children,
Query,
begin
_pipe = Path,
lustre@vdom@path:add(
_pipe,
Index,
erlang:element(3, Element)
)
end,
0
);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
{error, nil};
{text, _, _, _, _} ->
{error, nil}
end.
-file("src/lustre/dev/query.gleam", 264).
?DOC(
" Find the first element in a view that matches the given [`Query`](#Query).\n"
" This is useful for tests when combined with [`element.to_readable_string`](../element.html#to_readable_string),\n"
" allowing you to render large views but take more precise snapshots.\n"
).
-spec find(lustre@vdom@vnode:element(SVE), 'query'()) -> {ok,
lustre@vdom@vnode:element(SVE)} |
{error, nil}.
find(Root, Query) ->
case find_path(Root, Query, 0, root) of
{ok, {Element, _}} ->
{ok, Element};
{error, _} ->
{error, nil}
end.
-file("src/lustre/dev/query.gleam", 527).
?DOC(
" Check if an element or any of its descendants match the given\n"
" [`Selector`](#Selector).\n"
).
-spec has(lustre@vdom@vnode:element(any()), selector()) -> boolean().
has(Element, Selector) ->
case find(Element, {find_element, Selector}) of
{ok, _} ->
true;
{error, _} ->
false
end.
-file("src/lustre/dev/query.gleam", 391).
-spec find_descendant_in_list(
list(lustre@vdom@vnode:element(SWP)),
selector(),
lustre@vdom@path:path(),
integer()
) -> {ok, {lustre@vdom@vnode:element(SWP), lustre@vdom@path:path()}} |
{error, nil}.
find_descendant_in_list(Elements, Selector, Path, Index) ->
case Elements of
[] ->
{error, nil};
[First | Rest] ->
case matches(First, Selector) of
true ->
{ok,
{First,
lustre@vdom@path:add(
Path,
Index,
erlang:element(3, First)
)}};
false ->
Child = lustre@vdom@path:add(
Path,
Index,
erlang:element(3, First)
),
case find_descendant(First, Selector, Child) of
{ok, Element} ->
{ok, Element};
{error, _} ->
find_descendant_in_list(
Rest,
Selector,
Path,
Index + 1
)
end
end
end.
-file("src/lustre/dev/query.gleam", 374).
-spec find_descendant(
lustre@vdom@vnode:element(SWK),
selector(),
lustre@vdom@path:path()
) -> {ok, {lustre@vdom@vnode:element(SWK), lustre@vdom@path:path()}} |
{error, nil}.
find_descendant(Parent, Selector, Path) ->
case find_direct_child(Parent, Selector, Path) of
{ok, Element} ->
{ok, Element};
{error, _} ->
case Parent of
{element, _, _, _, _, _, _, Children, _, _, _} ->
find_descendant_in_list(Children, Selector, Path, 0);
{fragment, _, _, _, Children, _} ->
find_descendant_in_list(Children, Selector, Path, 0);
{unsafe_inner_html, _, _, _, _, _, _, _} ->
{error, nil};
{text, _, _, _, _} ->
{error, nil}
end
end.