mod palette;
pub use palette::*;
use std::marker::PhantomData;
use ratatui::style::Style;
use ratatui_kit_macros::Props;
use crate::{AnyElement, Component, ComponentUpdater, Context, Hooks, UseContext};
pub trait ComponentTheme: Clone + Default + 'static {
fn from_palette(palette: &Palette) -> Self;
}
pub(crate) fn resolve_style(theme: Style, override_style: Option<Style>) -> Style {
theme.patch(override_style.unwrap_or_default())
}
mod private {
pub trait Sealed {}
impl Sealed for crate::Hooks<'_, '_> {}
}
pub trait UseTheme: private::Sealed {
fn use_palette(&self) -> Palette;
fn use_component_theme<T: ComponentTheme>(&self) -> T;
}
impl UseTheme for Hooks<'_, '_> {
fn use_palette(&self) -> Palette {
self.try_use_context::<Palette>()
.map(|p| *p)
.unwrap_or_default()
}
fn use_component_theme<T: ComponentTheme>(&self) -> T {
match self.try_use_context::<T>() {
Some(t) => t.clone(),
None => T::from_palette(&self.use_palette()),
}
}
}
impl ComponentUpdater<'_, '_> {
pub fn use_palette(&self) -> Palette {
self.get_context::<Palette>()
.map(|p| *p)
.unwrap_or_default()
}
pub fn use_component_theme<T: ComponentTheme>(&self) -> T {
match self.get_context::<T>() {
Some(t) => t.clone(),
None => T::from_palette(&self.use_palette()),
}
}
}
#[derive(Default, Props)]
pub struct PaletteProviderProps<'a> {
pub children: Vec<AnyElement<'a>>,
pub palette: Palette,
}
pub struct PaletteProvider;
impl Component for PaletteProvider {
type Props<'a> = PaletteProviderProps<'a>;
fn new(_props: &Self::Props<'_>) -> Self {
Self
}
fn update(
&mut self,
props: &mut Self::Props<'_>,
_hooks: Hooks,
updater: &mut ComponentUpdater,
) {
updater.set_transparent_layout(true);
let mut ctx = Context::owned(props.palette);
updater.update_children(props.children.iter_mut(), Some(ctx.borrow()));
}
}
#[derive(Props)]
pub struct ThemeOverrideProps<'a, T>
where
T: ComponentTheme,
{
pub children: Vec<AnyElement<'a>>,
pub theme: T,
}
impl<T> Default for ThemeOverrideProps<'_, T>
where
T: ComponentTheme,
{
fn default() -> Self {
Self {
children: Vec::new(),
theme: T::default(),
}
}
}
pub struct ThemeOverride<T>(PhantomData<fn() -> T>);
impl<T> Component for ThemeOverride<T>
where
T: ComponentTheme,
{
type Props<'a> = ThemeOverrideProps<'a, T>;
fn new(_props: &Self::Props<'_>) -> Self {
Self(PhantomData)
}
fn update(
&mut self,
props: &mut Self::Props<'_>,
_hooks: Hooks,
updater: &mut ComponentUpdater,
) {
updater.set_transparent_layout(true);
let mut ctx = Context::owned(props.theme.clone());
updater.update_children(props.children.iter_mut(), Some(ctx.borrow()));
}
}