///|
pub struct Attr {
name : String
value : String
} derive(Debug, Eq)
///|
pub impl Show for Attr with fn output(self : Attr, logger : &Logger) -> Unit {
logger.write_string("Attr(\{self.name}=\{self.value})")
}
///|
pub struct EventBinding {
event : String
message : String
} derive(Debug, Eq)
///|
pub impl Show for EventBinding with fn output(
self : EventBinding,
logger : &Logger,
) -> Unit {
logger.write_string("EventBinding(\{self.event}->\{self.message})")
}
///|
pub struct Node {
kind : String
key : String
attrs : Array[Attr]
events : Array[EventBinding]
children : Array[Node]
text : String
list_total_count : Int
list_visible_count : Int
} derive(Debug, Eq)
///|
pub impl Show for Node with fn output(self : Node, logger : &Logger) -> Unit {
logger.write_string(
"Node(kind=\{self.kind}, key=\{self.key}, attrs=\{self.attrs.length()}, events=\{self.events.length()}, children=\{self.children.length()}, text=\{self.text.length()}, list_total=\{self.list_total_count}, list_visible=\{self.list_visible_count})",
)
}
///|
pub fn attr(name : String, value : String) -> Attr {
{ name, value }
}
///|
pub fn class_name(value : String) -> Attr {
attr("class", value)
}
///|
pub fn id(value : String) -> Attr {
attr("id", value)
}
///|
pub fn data(name : String, value : String) -> Attr {
attr("data-\{name}", value)
}
///|
pub fn event(event : String, message : String) -> EventBinding {
{ event, message }
}
///|
pub fn tap(message : String) -> EventBinding {
event("tap", message)
}
///|
pub fn node(
kind~ : String,
key? : String = "",
attrs? : Array[Attr] = [],
events? : Array[EventBinding] = [],
children? : Array[Node] = [],
text? : String = "",
list_total_count? : Int = 0,
list_visible_count? : Int = 0,
) -> Node {
{
kind,
key,
attrs,
events,
children,
text,
list_total_count,
list_visible_count,
}
}
///|
pub fn keyed(key : String, child : Node) -> Node {
{
kind: child.kind,
key,
attrs: child.attrs,
events: child.events,
children: child.children,
text: child.text,
list_total_count: child.list_total_count,
list_visible_count: child.list_visible_count,
}
}
///|
pub fn page(children : Array[Node]) -> Node {
node(kind="page", children~)
}
///|
pub fn view(children : Array[Node]) -> Node {
node(kind="view", children~)
}
///|
pub fn view_with_attrs(attrs : Array[Attr], children : Array[Node]) -> Node {
node(kind="view", attrs~, children~)
}
///|
pub fn scroll_view(children : Array[Node]) -> Node {
node(kind="scroll-view", children~)
}
///|
pub fn text(value : String) -> Node {
node(kind="text", text=value)
}
///|
pub fn input(
name~ : String,
value? : String = "",
input_message? : String = "",
) -> Node {
let events = if input_message == "" {
[]
} else {
[event("input", input_message)]
}
node(kind="input", attrs=[attr("name", name), attr("value", value)], events~)
}
///|
pub fn form(submit_message : String, children : Array[Node]) -> Node {
node(kind="form", events=[event("submit", submit_message)], children~)
}
///|
pub fn[Item] list(items : Array[Item], render : (Item) -> Node) -> Node {
let children : Array[Node] = []
for item in items {
children.push(render(item))
}
node(kind="view", attrs=[class_name("bunnia-list")], children~)
}
///|
pub fn[Item] windowed_list(
items : Array[Item],
total_count~ : Int,
offset? : Int = 0,
render~ : (Item) -> Node,
) -> Node {
let children : Array[Node] = []
for item in items {
children.push(render(item))
}
node(
kind="windowed-list",
attrs=[
class_name("bunnia-list bunnia-list-windowed"),
data("bunnia-list-mode", "windowed"),
data("total-count", total_count.to_string()),
data("visible-start", offset.to_string()),
data("visible-count", items.length().to_string()),
],
children~,
list_total_count=total_count,
list_visible_count=items.length(),
)
}
///|
pub fn when(condition : Bool, child : Node) -> Node {
if condition {
child
} else {
view([])
}
}
///|
pub fn image(src : String, alt : String) -> Node {
node(kind="image", attrs=[attr("src", src), attr("alt", alt)])
}
///|
pub fn button(label : String, message : String) -> Node {
node(kind="button", events=[tap(message)], children=[text(label)])
}
///|
pub fn canvas(canvas_id : String) -> Node {
node(kind="canvas", attrs=[id(canvas_id)])
}
///|
pub fn custom(
kind : String,
attrs : Array[Attr],
children : Array[Node],
) -> Node {
node(kind~, attrs~, children~)
}
///|
pub fn node_count(root : Node) -> Int {
let mut count = 1
for child in root.children {
count += node_count(child)
}
count
}
///|
pub fn max_depth(root : Node) -> Int {
let mut depth = 1
for child in root.children {
let child_depth = max_depth(child) + 1
if child_depth > depth {
depth = child_depth
}
}
depth
}