///|
/// One class of a class list: a name that is always there, or a name that is
/// there only while its flag holds.
///
/// templ takes `any` here and switches on the dynamic type — a plain string, a
/// `templ.KV`, a map of names to flags. MoonBit has no such type, so the list is
/// written out instead, and the maps templ accepted are read by the caller.
pub(all) enum CSSClass {
Name(String)
Toggle(KV[String, Bool])
}
///|
/// A list of class names, templ's `templ.CSSClasses`. `class={ ... }` renders it
/// into one attribute value.
pub(all) struct CSSClasses {
priv items : Array[CSSClass]
}
///|
pub fn CSSClasses::new(items : Array[CSSClass]) -> CSSClasses {
{ items, }
}
///|
/// The names that are on, in the order they first appeared.
///
/// A flag is read the way templ's processor reads one: it is the *last* flag
/// written for a name that decides, while the order comes from the *first* time
/// the name was written. So `["a", KV("a", false)]` renders nothing at all, and
/// `["a", "a"]` renders `a` once — both are templ's behaviour, and both are
/// pinned by tests below.
pub impl Show for CSSClasses with fn output(self, logger) {
let enabled : Map[String, Bool] = Map([])
let order : Array[String] = []
for item in self.items {
let (name, on) = match item {
Name(name) => (name, true)
Toggle(pair) => (pair.key, pair.value)
}
enabled[name] = on
order.push(name)
}
let rendered : Map[String, Unit] = Map([])
let mut first = true
for name in order {
if enabled.get(name) == Some(true) && !rendered.contains(name) {
if !first {
logger.write_string(" ")
}
first = false
logger.write_string(name)
rendered[name] = ()
}
}
}
///|
pub extend CSSClasses with Show::{to_string, output}