//// Stack container widget builder. import gleam/dict import gleam/list import gleam/option.{type Option, None} import plushie/node.{type Node, Node} import plushie/prop/a11y.{type A11y} import plushie/prop/length.{type Length} import plushie/widget/build pub opaque type Stack { Stack( id: String, children: List(Node), width: Option(Length), height: Option(Length), clip: Option(Bool), a11y: Option(A11y), ) } /// Create a new stack builder. pub fn new(id: String) -> Stack { Stack(id:, children: [], width: None, height: None, clip: None, a11y: None) } /// Set the width. pub fn width(s: Stack, w: Length) -> Stack { Stack(..s, width: option.Some(w)) } /// Set the height. pub fn height(s: Stack, h: Length) -> Stack { Stack(..s, height: option.Some(h)) } /// Set whether overflowing content is clipped. pub fn clip(s: Stack, c: Bool) -> Stack { Stack(..s, clip: option.Some(c)) } /// Add a child node. pub fn push(s: Stack, child: Node) -> Stack { Stack(..s, children: list.append(s.children, [child])) } /// Add multiple child nodes. pub fn extend(s: Stack, children: List(Node)) -> Stack { Stack(..s, children: list.append(s.children, children)) } /// Set accessibility properties for this widget. pub fn a11y(s: Stack, a: A11y) -> Stack { Stack(..s, a11y: option.Some(a)) } /// Option type for stack properties. pub type Opt { Width(Length) Height(Length) Clip(Bool) A11y(A11y) } /// Apply a list of options to a stack builder. pub fn with_opts(s: Stack, opts: List(Opt)) -> Stack { list.fold(opts, s, fn(st, opt) { case opt { Width(w) -> width(st, w) Height(h) -> height(st, h) Clip(v) -> clip(st, v) A11y(a) -> a11y(st, a) } }) } /// Build the stack into a renderable Node. pub fn build(s: Stack) -> Node { let props = dict.new() |> build.put_optional("width", s.width, length.to_prop_value) |> build.put_optional("height", s.height, length.to_prop_value) |> build.put_optional_bool("clip", s.clip) |> build.put_optional("a11y", s.a11y, a11y.to_prop_value) Node(id: s.id, kind: "stack", props:, children: s.children, meta: dict.new()) }