1use gpui::AnyElement;
6use smallvec::SmallVec;
7
8use crate::prelude::*;
9
10#[derive(IntoElement, RegisterComponent)]
14pub struct Table {
15 children: SmallVec<[AnyElement; 3]>,
16 caption: Option<AnyElement>,
17}
18
19impl Table {
20 pub fn new() -> Self {
21 Self {
22 children: SmallVec::new(),
23 caption: None,
24 }
25 }
26
27 pub fn caption(mut self, caption: impl IntoElement) -> Self {
28 self.caption = Some(caption.into_any_element());
29 self
30 }
31}
32
33impl Default for Table {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl ParentElement for Table {
40 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
41 self.children.extend(elements);
42 }
43}
44
45impl RenderOnce for Table {
46 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
47 v_flex()
48 .w_full()
49 .when_some(self.caption, |this, caption| this.child(caption))
50 .child(
51 v_flex()
52 .w_full()
53 .overflow_hidden()
54 .rounded_md()
55 .border_1()
56 .border_color(semantic::border(cx))
57 .children(self.children),
58 )
59 }
60}
61
62#[derive(IntoElement)]
64pub struct TableHeader {
65 children: SmallVec<[AnyElement; 1]>,
66}
67
68impl TableHeader {
69 pub fn new() -> Self {
70 Self {
71 children: SmallVec::new(),
72 }
73 }
74}
75
76impl Default for TableHeader {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl ParentElement for TableHeader {
83 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
84 self.children.extend(elements);
85 }
86}
87
88impl RenderOnce for TableHeader {
89 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
90 v_flex()
91 .w_full()
92 .bg(semantic::elevated_surface(cx))
93 .border_b_1()
94 .border_color(semantic::border_muted(cx))
95 .children(self.children)
96 }
97}
98
99#[derive(IntoElement)]
101pub struct TableBody {
102 children: SmallVec<[AnyElement; 4]>,
103}
104
105impl TableBody {
106 pub fn new() -> Self {
107 Self {
108 children: SmallVec::new(),
109 }
110 }
111}
112
113impl Default for TableBody {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119impl ParentElement for TableBody {
120 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
121 self.children.extend(elements);
122 }
123}
124
125impl RenderOnce for TableBody {
126 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
127 v_flex().w_full().children(self.children)
128 }
129}
130
131#[derive(IntoElement)]
133pub struct TableFooter {
134 children: SmallVec<[AnyElement; 1]>,
135}
136
137impl TableFooter {
138 pub fn new() -> Self {
139 Self {
140 children: SmallVec::new(),
141 }
142 }
143}
144
145impl Default for TableFooter {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151impl ParentElement for TableFooter {
152 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
153 self.children.extend(elements);
154 }
155}
156
157impl RenderOnce for TableFooter {
158 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
159 v_flex()
160 .w_full()
161 .bg(semantic::elevated_surface(cx))
162 .border_t_1()
163 .border_color(semantic::border_muted(cx))
164 .children(self.children)
165 }
166}
167
168#[derive(IntoElement)]
170pub struct TableRow {
171 children: SmallVec<[AnyElement; 4]>,
172 hover: bool,
173}
174
175impl TableRow {
176 pub fn new() -> Self {
177 Self {
178 children: SmallVec::new(),
179 hover: true,
180 }
181 }
182
183 pub fn hover(mut self, hover: bool) -> Self {
184 self.hover = hover;
185 self
186 }
187}
188
189impl Default for TableRow {
190 fn default() -> Self {
191 Self::new()
192 }
193}
194
195impl ParentElement for TableRow {
196 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
197 self.children.extend(elements);
198 }
199}
200
201impl RenderOnce for TableRow {
202 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
203 let hover_bg = semantic::hover_bg(cx);
204 h_flex()
205 .w_full()
206 .border_b_1()
207 .border_color(semantic::border_muted(cx))
208 .when(self.hover, |this| this.hover(move |s| s.bg(hover_bg)))
209 .children(self.children)
210 }
211}
212
213#[derive(IntoElement)]
215pub struct TableHead {
216 children: SmallVec<[AnyElement; 1]>,
217 align_end: bool,
218}
219
220impl TableHead {
221 pub fn new() -> Self {
222 Self {
223 children: SmallVec::new(),
224 align_end: false,
225 }
226 }
227
228 pub fn align_end(mut self, align_end: bool) -> Self {
229 self.align_end = align_end;
230 self
231 }
232}
233
234impl Default for TableHead {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl ParentElement for TableHead {
241 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
242 self.children.extend(elements);
243 }
244}
245
246impl RenderOnce for TableHead {
247 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
248 h_flex()
249 .flex_1()
250 .px_4()
251 .py_3()
252 .when(self.align_end, |this| this.justify_end())
253 .children(self.children)
254 }
255}
256
257#[derive(IntoElement)]
259pub struct TableCell {
260 children: SmallVec<[AnyElement; 1]>,
261 align_end: bool,
262}
263
264impl TableCell {
265 pub fn new() -> Self {
266 Self {
267 children: SmallVec::new(),
268 align_end: false,
269 }
270 }
271
272 pub fn align_end(mut self, align_end: bool) -> Self {
273 self.align_end = align_end;
274 self
275 }
276}
277
278impl Default for TableCell {
279 fn default() -> Self {
280 Self::new()
281 }
282}
283
284impl ParentElement for TableCell {
285 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
286 self.children.extend(elements);
287 }
288}
289
290impl RenderOnce for TableCell {
291 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
292 h_flex()
293 .flex_1()
294 .px_4()
295 .py_3()
296 .when(self.align_end, |this| this.justify_end())
297 .children(self.children)
298 }
299}
300
301#[derive(IntoElement)]
303pub struct TableCaption {
304 label: SharedString,
305}
306
307impl TableCaption {
308 pub fn new(label: impl Into<SharedString>) -> Self {
309 Self {
310 label: label.into(),
311 }
312 }
313}
314
315impl RenderOnce for TableCaption {
316 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
317 div().mb_2().child(
318 Label::new(self.label)
319 .size(LabelSize::Small)
320 .color(Color::Muted),
321 )
322 }
323}
324
325impl Component for Table {
326 fn scope() -> ComponentScope {
327 ComponentScope::DataDisplay
328 }
329
330 fn description() -> Option<&'static str> {
331 Some("Lightweight static table primitives (Root/Header/Body/Row/Head/Cell/Caption).")
332 }
333
334 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
335 Some(
336 Table::new()
337 .caption(TableCaption::new("A list of recent invoices."))
338 .child(
339 TableHeader::new().child(
340 TableRow::new().hover(false).children([
341 TableHead::new()
342 .child(Label::new("Invoice").weight(gpui::FontWeight::SEMIBOLD)),
343 TableHead::new()
344 .align_end(true)
345 .child(Label::new("Amount").weight(gpui::FontWeight::SEMIBOLD)),
346 ]),
347 ),
348 )
349 .child(
350 TableBody::new()
351 .child(
352 TableRow::new().children([
353 TableCell::new().child(Label::new("INV001")),
354 TableCell::new()
355 .align_end(true)
356 .child(Label::new("$250.00")),
357 ]),
358 )
359 .child(
360 TableRow::new().children([
361 TableCell::new().child(Label::new("INV002")),
362 TableCell::new()
363 .align_end(true)
364 .child(Label::new("$150.00")),
365 ]),
366 ),
367 )
368 .into_any_element(),
369 )
370 }
371}