use rdom_core::NodeMut;
use rdom_style::property_dispatch;
use super::SetPropertyError;
use super::serialize::css_text_of;
use crate::TuiExt;
use crate::cssom::inline::{sync_from_attribute, write_style_attribute};
pub struct StyleDeclarationMut<'a> {
node: NodeMut<'a, TuiExt>,
}
impl<'a> StyleDeclarationMut<'a> {
pub(crate) fn new(node: NodeMut<'a, TuiExt>) -> Self {
Self { node }
}
pub fn set_property(&mut self, name: &str, value: &str) -> rdom_core::Result<()> {
swallow_parse_errors(self.try_write_inner(name, value, false))
}
pub fn set_property_important(&mut self, name: &str, value: &str) -> rdom_core::Result<()> {
swallow_parse_errors(self.try_write_inner(name, value, true))
}
pub fn try_set_property(&mut self, name: &str, value: &str) -> Result<(), SetPropertyError> {
self.try_write_inner(name, value, false)
}
pub fn try_set_property_important(
&mut self,
name: &str,
value: &str,
) -> Result<(), SetPropertyError> {
self.try_write_inner(name, value, true)
}
pub fn remove_property(&mut self, name: &str) -> rdom_core::Result<String> {
let id = self.node.id();
let dom = self.node.dom_mut();
sync_from_attribute(dom, id);
let mut nm = dom.node_mut(id);
let Some(ext) = nm.ext_mut() else {
return Ok(String::new());
};
let prev =
property_dispatch::serialize(name, ext.inline_style_or_empty()).unwrap_or_default();
let removed = ext
.inline_style
.as_deref_mut()
.is_some_and(|style| property_dispatch::remove(name, style));
if !removed {
return Ok(prev);
}
let css_text = css_text_of(ext.inline_style_or_empty());
let _ = nm;
write_style_attribute(dom, id, &css_text)?;
Ok(prev)
}
pub fn set_css_text(&mut self, css: &str) -> rdom_core::Result<()> {
let id = self.node.id();
let dom = self.node.dom_mut();
let parsed = rdom_css::parse_inline(css);
let mut nm = dom.node_mut(id);
let Some(ext) = nm.ext_mut() else {
return Ok(());
};
ext.set_inline_style(parsed.style);
let css_text = css_text_of(ext.inline_style_or_empty());
let _ = nm;
write_style_attribute(dom, id, &css_text)?;
Ok(())
}
fn try_write_inner(
&mut self,
name: &str,
value: &str,
important: bool,
) -> Result<(), SetPropertyError> {
let id = self.node.id();
let dom = self.node.dom_mut();
sync_from_attribute(dom, id);
let mut nm = dom.node_mut(id);
let Some(ext) = nm.ext_mut() else {
return Ok(());
};
let style = ext.inline_style_mut();
property_dispatch::set(name, value, style)?;
if let Some(custom) = name.strip_prefix("--")
&& let Some(d) = style
.custom_properties
.iter_mut()
.find(|d| d.name == custom)
{
d.important = important;
}
if let Some(mask) = property_dispatch::property_mask(name) {
if important {
style.important |= mask;
} else {
style.important = style.important.without(mask);
}
}
let css_text = css_text_of(ext.inline_style_or_empty());
let _ = nm;
write_style_attribute(dom, id, &css_text)?;
Ok(())
}
}
fn swallow_parse_errors(result: Result<(), SetPropertyError>) -> rdom_core::Result<()> {
match result {
Ok(()) | Err(SetPropertyError::Parse(_)) => Ok(()),
Err(SetPropertyError::Tree(e)) => Err(e),
}
}