Current section
Files
Jump to
Current section
Files
src/plushie@testing@element.erl
-module(plushie@testing@element).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/plushie/testing/element.gleam").
-export([from_node/1, find/2, text/1, prop/2, id/1, kind/1, children/1, has_children/1, child_at/2, find_within/2, find_all/2, a11y/1, resolved_a11y/1, local_id/1]).
-export_type([element/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.
?MODULEDOC(
" Element: a query-friendly wrapper around a tree Node.\n"
"\n"
" Elements provide convenient accessors for testing: find by ID,\n"
" extract text content, read props, and traverse children.\n"
).
-type element() :: {element, plushie@node:node_()}.
-file("src/plushie/testing/element.gleam", 19).
?DOC(" Wrap a Node as an Element.\n").
-spec from_node(plushie@node:node_()) -> element().
from_node(Node) ->
{element, Node}.
-file("src/plushie/testing/element.gleam", 24).
?DOC(" Find an element by ID in a normalized tree.\n").
-spec find(plushie@node:node_(), binary()) -> gleam@option:option(element()).
find(Root, Target) ->
case plushie@tree:find(Root, Target) of
{some, Node} ->
{some, {element, Node}};
none ->
none
end.
-file("src/plushie/testing/element.gleam", 39).
-spec find_first_string(
gleam@dict:dict(binary(), plushie@node:prop_value()),
list(binary())
) -> gleam@option:option(binary()).
find_first_string(Props, Keys) ->
case Keys of
[] ->
none;
[Key | Rest] ->
case gleam_stdlib:map_get(Props, Key) of
{ok, {string_val, S}} ->
{some, S};
_ ->
find_first_string(Props, Rest)
end
end.
-file("src/plushie/testing/element.gleam", 33).
?DOC(
" Extract text content from an element.\n"
" Checks props in order: \"content\", \"label\", \"value\", \"placeholder\".\n"
).
-spec text(element()) -> gleam@option:option(binary()).
text(Element) ->
Props = erlang:element(4, erlang:element(2, Element)),
Keys = [<<"content"/utf8>>,
<<"label"/utf8>>,
<<"value"/utf8>>,
<<"placeholder"/utf8>>],
find_first_string(Props, Keys).
-file("src/plushie/testing/element.gleam", 54).
?DOC(" Get a prop value by key.\n").
-spec prop(element(), binary()) -> gleam@option:option(plushie@node:prop_value()).
prop(Element, Key) ->
case gleam_stdlib:map_get(
erlang:element(4, erlang:element(2, Element)),
Key
) of
{ok, Value} ->
{some, Value};
{error, _} ->
none
end.
-file("src/plushie/testing/element.gleam", 62).
?DOC(" Get the element's ID.\n").
-spec id(element()) -> binary().
id(Element) ->
erlang:element(2, erlang:element(2, Element)).
-file("src/plushie/testing/element.gleam", 67).
?DOC(" Get the element's kind (widget type).\n").
-spec kind(element()) -> binary().
kind(Element) ->
erlang:element(3, erlang:element(2, Element)).
-file("src/plushie/testing/element.gleam", 72).
?DOC(" Get the element's children as Elements.\n").
-spec children(element()) -> list(element()).
children(Element) ->
gleam@list:map(
erlang:element(5, erlang:element(2, Element)),
fun from_node/1
).
-file("src/plushie/testing/element.gleam", 77).
?DOC(" Check if the element has any children.\n").
-spec has_children(element()) -> boolean().
has_children(Element) ->
not gleam@list:is_empty(erlang:element(5, erlang:element(2, Element))).
-file("src/plushie/testing/element.gleam", 82).
?DOC(" Get a child element by index.\n").
-spec child_at(element(), integer()) -> gleam@option:option(element()).
child_at(Element, Index) ->
case gleam@list:drop(erlang:element(5, erlang:element(2, Element)), Index) of
[Child | _] ->
{some, from_node(Child)};
[] ->
none
end.
-file("src/plushie/testing/element.gleam", 90).
?DOC(" Find a descendant element by ID within this element's subtree.\n").
-spec find_within(element(), binary()) -> gleam@option:option(element()).
find_within(Element, Target) ->
find(erlang:element(2, Element), Target).
-file("src/plushie/testing/element.gleam", 95).
?DOC(" Collect all descendant elements matching a predicate.\n").
-spec find_all(element(), fun((element()) -> boolean())) -> list(element()).
find_all(Element, Predicate) ->
_pipe = plushie@tree:find_all(
erlang:element(2, Element),
fun(Node) -> Predicate(from_node(Node)) end
),
gleam@list:map(_pipe, fun from_node/1).
-file("src/plushie/testing/element.gleam", 106).
?DOC(
" Get the a11y props dict from an element.\n"
"\n"
" Returns an empty dict if no `a11y` key is set.\n"
).
-spec a11y(element()) -> gleam@dict:dict(binary(), plushie@node:prop_value()).
a11y(Element) ->
case gleam_stdlib:map_get(
erlang:element(4, erlang:element(2, Element)),
<<"a11y"/utf8>>
) of
{ok, {dict_val, M}} ->
M;
_ ->
maps:new()
end.
-file("src/plushie/testing/element.gleam", 127).
-spec infer_a11y(binary(), gleam@dict:dict(binary(), plushie@node:prop_value())) -> gleam@dict:dict(binary(), plushie@node:prop_value()).
infer_a11y(Kind, Props) ->
case Kind of
<<"text_input"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"placeholder"/utf8>>) of
{ok, {string_val, S}} when S =/= <<""/utf8>> ->
maps:from_list([{<<"description"/utf8>>, {string_val, S}}]);
_ ->
maps:new()
end;
<<"text_editor"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"placeholder"/utf8>>) of
{ok, {string_val, S}} when S =/= <<""/utf8>> ->
maps:from_list([{<<"description"/utf8>>, {string_val, S}}]);
_ ->
maps:new()
end;
<<"combo_box"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"placeholder"/utf8>>) of
{ok, {string_val, S}} when S =/= <<""/utf8>> ->
maps:from_list([{<<"description"/utf8>>, {string_val, S}}]);
_ ->
maps:new()
end;
<<"pick_list"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"placeholder"/utf8>>) of
{ok, {string_val, S}} when S =/= <<""/utf8>> ->
maps:from_list([{<<"description"/utf8>>, {string_val, S}}]);
_ ->
maps:new()
end;
<<"image"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"alt"/utf8>>) of
{ok, {string_val, S@1}} when S@1 =/= <<""/utf8>> ->
maps:from_list([{<<"label"/utf8>>, {string_val, S@1}}]);
_ ->
maps:new()
end;
<<"svg"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"alt"/utf8>>) of
{ok, {string_val, S@1}} when S@1 =/= <<""/utf8>> ->
maps:from_list([{<<"label"/utf8>>, {string_val, S@1}}]);
_ ->
maps:new()
end;
<<"qr_code"/utf8>> ->
case gleam_stdlib:map_get(Props, <<"alt"/utf8>>) of
{ok, {string_val, S@1}} when S@1 =/= <<""/utf8>> ->
maps:from_list([{<<"label"/utf8>>, {string_val, S@1}}]);
_ ->
maps:new()
end;
_ ->
maps:new()
end.
-file("src/plushie/testing/element.gleam", 119).
?DOC(
" Return the resolved a11y dict for this element.\n"
"\n"
" Layers render-pipeline inference (placeholder -> description for\n"
" text-entry widgets, alt -> label for media widgets) on top of the\n"
" normalized `a11y` prop. Kept aligned with the Rust SDK's\n"
" `resolve_a11y_for_node` so cross-SDK parity holds.\n"
).
-spec resolved_a11y(element()) -> gleam@dict:dict(binary(), plushie@node:prop_value()).
resolved_a11y(Element) ->
Explicit = a11y(Element),
Inferred = infer_a11y(
erlang:element(3, erlang:element(2, Element)),
erlang:element(4, erlang:element(2, Element))
),
maps:merge(Inferred, Explicit).
-file("src/plushie/testing/element.gleam", 149).
?DOC(" Get the local ID (last segment after \"/\" and \"#\").\n").
-spec local_id(element()) -> binary().
local_id(Element) ->
Path = case gleam@string:split_once(
erlang:element(2, erlang:element(2, Element)),
<<"#"/utf8>>
) of
{ok, {_, After}} ->
After;
{error, _} ->
erlang:element(2, erlang:element(2, Element))
end,
case gleam@string:split(Path, <<"/"/utf8>>) of
[] ->
Path;
Segments ->
case gleam@list:last(Segments) of
{ok, Last} ->
Last;
{error, _} ->
Path
end
end.