1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Separator component - Visual dividers for content sections.
use crate::theme::use_theme;
use kael::{prelude::FluentBuilder as _, *};
/// Orientation of the separator
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SeparatorOrientation {
/// Horizontal separator (default)
#[default]
Horizontal,
/// Vertical separator
Vertical,
}
/// Visual divider for separating content
///
/// # Example
///
/// ```rust,ignore
/// // Horizontal separator
/// Separator::new()
///
/// // Vertical separator
/// Separator::new()
/// .orientation(SeparatorOrientation::Vertical)
///
/// // With label
/// Separator::new()
/// .label("OR")
/// ```
#[derive(IntoElement)]
pub struct Separator {
orientation: SeparatorOrientation,
label: Option<SharedString>,
color: Option<Hsla>,
decorative: bool,
style: StyleRefinement,
}
impl Separator {
/// Create a new horizontal separator
pub fn new() -> Self {
Self {
orientation: SeparatorOrientation::default(),
label: None,
color: None,
decorative: true,
style: StyleRefinement::default(),
}
}
/// Create a horizontal separator
pub fn horizontal() -> Self {
Self::new()
}
/// Create a vertical separator
pub fn vertical() -> Self {
Self::new().orientation(SeparatorOrientation::Vertical)
}
/// Set the orientation
pub fn orientation(mut self, orientation: SeparatorOrientation) -> Self {
self.orientation = orientation;
self
}
/// Set an optional label to display on the separator
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
self.label = Some(label.into());
self
}
/// Set custom color for the separator line
pub fn color(mut self, color: impl Into<Hsla>) -> Self {
self.color = Some(color.into());
self
}
/// Set whether this is a decorative separator (for accessibility)
/// Decorative separators are hidden from screen readers
pub fn decorative(mut self, decorative: bool) -> Self {
self.decorative = decorative;
self
}
}
impl Styled for Separator {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for Separator {
fn render(self, _: &mut Window, _cx: &mut App) -> impl IntoElement {
let theme = use_theme();
let line_color = self.color.unwrap_or(theme.tokens.border);
let user_style = self.style;
div()
.flex()
.flex_shrink_0()
.items_center()
.justify_center()
.relative()
.when(
self.orientation == SeparatorOrientation::Horizontal,
|this| this.w_full().h(px(1.0)),
)
.when(self.orientation == SeparatorOrientation::Vertical, |this| {
this.h_full().w(px(1.0))
})
.child(
div()
.absolute()
.when(
self.orientation == SeparatorOrientation::Horizontal,
|this| this.w_full().h(px(1.0)),
)
.when(self.orientation == SeparatorOrientation::Vertical, |this| {
this.h_full().w(px(1.0))
})
.bg(line_color),
)
.when_some(self.label, |this, label| {
this.child(
div()
.px(px(8.0))
.py(px(4.0))
.text_xs()
.bg(theme.tokens.background)
.text_color(theme.tokens.muted_foreground)
.child(label),
)
})
.map(|this| {
let mut div = this;
div.style().refine(&user_style);
div
})
}
}
impl Default for Separator {
fn default() -> Self {
Self::new()
}
}