use std::rc::Rc;
use gpui::{
AnyElement, App, IntoElement, RenderOnce, SharedString, Window, prelude::FluentBuilder,
};
use gpui_kit_theme::ControlSize;
use crate::foundation::{Ident, Sizable};
use crate::navigation::accordion::{Accordion, AccordionSection};
const SECTION: &str = "header";
type ToggleHandler = Rc<dyn Fn(bool, &mut Window, &mut App)>;
#[derive(IntoElement)]
pub struct Collapsible {
ident: Ident,
title: SharedString,
description: Option<SharedString>,
open: bool,
disabled: bool,
size: ControlSize,
body: Option<AnyElement>,
on_toggle: Option<ToggleHandler>,
}
impl std::fmt::Debug for Collapsible {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Collapsible")
.field("ident", &self.ident)
.field("title", &self.title)
.field("open", &self.open)
.field("disabled", &self.disabled)
.field("has_body", &self.body.is_some())
.field("has_handler", &self.on_toggle.is_some())
.finish()
}
}
impl Collapsible {
pub fn new(ident: impl Into<Ident>, title: impl Into<SharedString>) -> Self {
Self {
ident: ident.into(),
title: title.into(),
description: None,
open: false,
disabled: false,
size: ControlSize::Md,
body: None,
on_toggle: None,
}
}
pub fn description(mut self, description: impl Into<SharedString>) -> Self {
self.description = Some(description.into());
self
}
pub fn open(mut self, open: bool) -> Self {
self.open = open;
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn body(mut self, body: impl IntoElement) -> Self {
self.body = Some(body.into_any_element());
self
}
pub fn on_toggle(mut self, handler: impl Fn(bool, &mut Window, &mut App) + 'static) -> Self {
self.on_toggle = Some(Rc::new(handler));
self
}
pub fn header_id(ident: &Ident) -> SharedString {
ident.child(SECTION).semantic_id()
}
}
impl Sizable for Collapsible {
fn control_size(mut self, size: ControlSize) -> Self {
self.size = size;
self
}
}
impl RenderOnce for Collapsible {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let mut section =
AccordionSection::new(SECTION, self.title.clone()).disabled(self.disabled);
if let Some(description) = self.description.clone() {
section = section.description(description);
}
if let Some(body) = self.body {
section = section.body(body);
}
Accordion::new(self.ident.clone())
.control_size(self.size)
.section(section)
.when(self.open, |accordion| accordion.expanded_ids(&[SECTION]))
.when_some(self.on_toggle, |accordion, handler| {
accordion.on_toggle(move |_, next, window, cx| handler(next, window, cx))
})
}
}