kael_ui 0.2.0

Professional shadcn-inspired UI component library for Kael. 100+ accessible components for building beautiful, performant desktop applications.
use crate::animations::easings;
use kael::{prelude::FluentBuilder as _, *};
use std::time::Duration;

#[derive(IntoElement)]
pub struct TextHighlight {
    id: ElementId,
    color: Option<Hsla>,
    duration: Duration,
    delay: Duration,
    children: Vec<AnyElement>,
    style: StyleRefinement,
}

impl TextHighlight {
    pub fn new(id: impl Into<ElementId>) -> Self {
        Self {
            id: id.into(),
            color: None,
            duration: Duration::from_millis(600),
            delay: Duration::from_millis(0),
            children: Vec::new(),
            style: StyleRefinement::default(),
        }
    }

    pub fn color(mut self, color: Hsla) -> Self {
        self.color = Some(color);
        self
    }

    pub fn duration(mut self, duration: Duration) -> Self {
        self.duration = duration;
        self
    }

    pub fn delay(mut self, delay: Duration) -> Self {
        self.delay = delay;
        self
    }
}

impl Styled for TextHighlight {
    fn style(&mut self) -> &mut StyleRefinement {
        &mut self.style
    }
}

impl ParentElement for TextHighlight {
    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
        self.children.extend(elements);
    }
}

impl RenderOnce for TextHighlight {
    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
        let highlight_color = self.color.unwrap_or(hsla(0.15, 0.9, 0.6, 0.3));
        let anim_id: ElementId = ElementId::Name(format!("{}-sweep", self.id).into());
        let total_duration =
            Duration::from_millis(self.duration.as_millis() as u64 + self.delay.as_millis() as u64);
        let delay = self.delay;
        let user_style = self.style;

        let overlay = div()
            .id(anim_id.clone())
            .absolute()
            .top_0()
            .left_0()
            .h_full()
            .bg(highlight_color)
            .with_animation(
                anim_id,
                Animation::new(total_duration).with_easing(easings::ease_out_cubic),
                move |el, delta| {
                    let t = if total_duration.as_millis() > 0 {
                        let delay_frac =
                            delay.as_millis() as f32 / total_duration.as_millis() as f32;
                        ((delta - delay_frac) / (1.0 - delay_frac)).clamp(0.0, 1.0)
                    } else {
                        1.0
                    };
                    el.w(relative(t))
                },
            );

        let mut container = div().relative().child(overlay).map(|mut el| {
            el.style().refine(&user_style);
            el
        });

        for child in self.children {
            container = container.child(div().relative().child(child));
        }

        container
    }
}