use gpui::AnyElement;
use smallvec::SmallVec;
use crate::prelude::*;
#[derive(IntoElement, RegisterComponent)]
pub struct Table {
children: SmallVec<[AnyElement; 3]>,
caption: Option<AnyElement>,
}
impl Table {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
caption: None,
}
}
pub fn caption(mut self, caption: impl IntoElement) -> Self {
self.caption = Some(caption.into_any_element());
self
}
}
impl Default for Table {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for Table {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for Table {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
v_flex()
.w_full()
.when_some(self.caption, |this, caption| this.child(caption))
.child(
v_flex()
.w_full()
.overflow_hidden()
.rounded_md()
.border_1()
.border_color(semantic::border(cx))
.children(self.children),
)
}
}
#[derive(IntoElement)]
pub struct TableHeader {
children: SmallVec<[AnyElement; 1]>,
}
impl TableHeader {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
}
}
}
impl Default for TableHeader {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableHeader {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableHeader {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
v_flex()
.w_full()
.bg(semantic::elevated_surface(cx))
.border_b_1()
.border_color(semantic::border_muted(cx))
.children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableBody {
children: SmallVec<[AnyElement; 4]>,
}
impl TableBody {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
}
}
}
impl Default for TableBody {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableBody {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableBody {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
v_flex().w_full().children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableFooter {
children: SmallVec<[AnyElement; 1]>,
}
impl TableFooter {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
}
}
}
impl Default for TableFooter {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableFooter {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableFooter {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
v_flex()
.w_full()
.bg(semantic::elevated_surface(cx))
.border_t_1()
.border_color(semantic::border_muted(cx))
.children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableRow {
children: SmallVec<[AnyElement; 4]>,
hover: bool,
}
impl TableRow {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
hover: true,
}
}
pub fn hover(mut self, hover: bool) -> Self {
self.hover = hover;
self
}
}
impl Default for TableRow {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableRow {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableRow {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let hover_bg = semantic::hover_bg(cx);
h_flex()
.w_full()
.border_b_1()
.border_color(semantic::border_muted(cx))
.when(self.hover, |this| this.hover(move |s| s.bg(hover_bg)))
.children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableHead {
children: SmallVec<[AnyElement; 1]>,
align_end: bool,
}
impl TableHead {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
align_end: false,
}
}
pub fn align_end(mut self, align_end: bool) -> Self {
self.align_end = align_end;
self
}
}
impl Default for TableHead {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableHead {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableHead {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
h_flex()
.flex_1()
.px_4()
.py_3()
.when(self.align_end, |this| this.justify_end())
.children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableCell {
children: SmallVec<[AnyElement; 1]>,
align_end: bool,
}
impl TableCell {
pub fn new() -> Self {
Self {
children: SmallVec::new(),
align_end: false,
}
}
pub fn align_end(mut self, align_end: bool) -> Self {
self.align_end = align_end;
self
}
}
impl Default for TableCell {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for TableCell {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for TableCell {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
h_flex()
.flex_1()
.px_4()
.py_3()
.when(self.align_end, |this| this.justify_end())
.children(self.children)
}
}
#[derive(IntoElement)]
pub struct TableCaption {
label: SharedString,
}
impl TableCaption {
pub fn new(label: impl Into<SharedString>) -> Self {
Self {
label: label.into(),
}
}
}
impl RenderOnce for TableCaption {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
div().mb_2().child(
Label::new(self.label)
.size(LabelSize::Small)
.color(Color::Muted),
)
}
}
impl Component for Table {
fn scope() -> ComponentScope {
ComponentScope::DataDisplay
}
fn description() -> Option<&'static str> {
Some("Lightweight static table primitives (Root/Header/Body/Row/Head/Cell/Caption).")
}
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
Some(
Table::new()
.caption(TableCaption::new("A list of recent invoices."))
.child(
TableHeader::new().child(
TableRow::new().hover(false).children([
TableHead::new()
.child(Label::new("Invoice").weight(gpui::FontWeight::SEMIBOLD)),
TableHead::new()
.align_end(true)
.child(Label::new("Amount").weight(gpui::FontWeight::SEMIBOLD)),
]),
),
)
.child(
TableBody::new()
.child(
TableRow::new().children([
TableCell::new().child(Label::new("INV001")),
TableCell::new()
.align_end(true)
.child(Label::new("$250.00")),
]),
)
.child(
TableRow::new().children([
TableCell::new().child(Label::new("INV002")),
TableCell::new()
.align_end(true)
.child(Label::new("$150.00")),
]),
),
)
.into_any_element(),
)
}
}