woocraft 0.4.5

GPUI components lib for Woocraft design system.
Documentation
use std::rc::Rc;

use gpui::{
  AnyElement, App, ClickEvent, ElementId, InteractiveElement as _, IntoElement, MouseButton,
  ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement,
  Styled, Window, div, prelude::FluentBuilder as _,
};

use crate::{ActiveTheme, StyledExt};

type LinkClickHandler = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>;

#[derive(IntoElement)]
pub struct Link {
  id: ElementId,
  style: StyleRefinement,
  href: Option<SharedString>,
  disabled: bool,
  on_click: Option<LinkClickHandler>,
  children: Vec<AnyElement>,
}

impl Link {
  pub fn new(id: impl Into<ElementId>) -> Self {
    Self {
      id: id.into(),
      style: StyleRefinement::default(),
      href: None,
      disabled: false,
      on_click: None,
      children: Vec::new(),
    }
  }

  pub fn href(mut self, href: impl Into<SharedString>) -> Self {
    self.href = Some(href.into());
    self
  }

  pub fn on_click(
    mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
  ) -> Self {
    self.on_click = Some(Rc::new(handler));
    self
  }
}

impl_disableable!(Link);
impl_styled!(Link);
impl_parent_element!(Link);

impl RenderOnce for Link {
  fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
    let href = self.href.clone();
    let on_click = self.on_click.clone();
    let base_color = if self.disabled {
      cx.theme().muted_foreground
    } else {
      cx.theme().primary
    };

    div()
      .id(self.id)
      .text_color(base_color)
      .text_decoration_1()
      .text_decoration_color(base_color)
      .when(!self.disabled, |this| {
        this
          .cursor_pointer()
          .hover(|this| this.opacity(0.85))
          .active(|this| this.opacity(0.7))
      })
      .when(!self.disabled, |this| {
        this.on_mouse_down(MouseButton::Left, |_, _, cx| {
          cx.stop_propagation();
        })
      })
      .when(!self.disabled, |this| {
        this.on_click(move |event, window, cx| {
          if let Some(href) = href.as_ref() {
            cx.open_url(href);
          }

          if let Some(on_click) = on_click.as_ref() {
            on_click(event, window, cx);
          }
        })
      })
      .children(self.children)
      .refine_style(&self.style)
  }
}