@@ -7,6 +7,7 @@ use gpui::HitboxBehavior;
use language::LanguageName;
use log::Level;
pub use path_range::{LineCol, PathWithRange};
+use ui::Checkbox;
use std::borrow::Cow;
use std::iter;
@@ -795,7 +796,7 @@ impl Element for MarkdownElement {
let mut code_block_ids = HashSet::default();
let mut current_img_block_range: Option<Range<usize>> = None;
- for (range, event) in parsed_markdown.events.iter() {
+ for (index, (range, event)) in parsed_markdown.events.iter().enumerate() {
// Skip alt text for images that rendered
if let Some(current_img_block_range) = ¤t_img_block_range
&& current_img_block_range.end > range.end
@@ -945,13 +946,29 @@ impl Element for MarkdownElement {
MarkdownTag::HtmlBlock => builder.push_div(div(), range, markdown_end),
MarkdownTag::List(bullet_index) => {
builder.push_list(*bullet_index);
- builder.push_div(div().pl_4(), range, markdown_end);
+ builder.push_div(div().pl_2p5(), range, markdown_end);
}
MarkdownTag::Item => {
- let bullet = if let Some(bullet_index) = builder.next_bullet_index() {
- format!("{}.", bullet_index)
+ let bullet = if let Some((_, MarkdownEvent::TaskListMarker(checked))) =
+ parsed_markdown.events.get(index.saturating_add(1))
+ {
+ let source = &parsed_markdown.source()[range.clone()];
+
+ Checkbox::new(
+ ElementId::Name(source.to_string().into()),
+ if *checked {
+ ToggleState::Selected
+ } else {
+ ToggleState::Unselected
+ },
+ )
+ .fill()
+ .visualization_only(true)
+ .into_any_element()
+ } else if let Some(bullet_index) = builder.next_bullet_index() {
+ div().child(format!("{}.", bullet_index)).into_any_element()
} else {
- "•".to_string()
+ div().child("•").into_any_element()
};
builder.push_div(
div()
@@ -1226,6 +1243,9 @@ impl Element for MarkdownElement {
}
MarkdownEvent::SoftBreak => builder.push_text(" ", range.clone()),
MarkdownEvent::HardBreak => builder.push_text("\n", range.clone()),
+ MarkdownEvent::TaskListMarker(_) => {
+ // handled inside the `MarkdownTag::Item` case
+ }
_ => log::debug!("unsupported markdown event {:?}", event),
}
}
@@ -44,15 +44,16 @@ pub enum ToggleStyle {
pub struct Checkbox {
id: ElementId,
toggle_state: ToggleState,
+ style: ToggleStyle,
disabled: bool,
placeholder: bool,
- on_click: Option<Box<dyn Fn(&ToggleState, &ClickEvent, &mut Window, &mut App) + 'static>>,
filled: bool,
- style: ToggleStyle,
- tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
+ visualization: bool,
label: Option<SharedString>,
label_size: LabelSize,
label_color: Color,
+ tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
+ on_click: Option<Box<dyn Fn(&ToggleState, &ClickEvent, &mut Window, &mut App) + 'static>>,
}
impl Checkbox {
@@ -61,15 +62,16 @@ impl Checkbox {
Self {
id: id.into(),
toggle_state: checked,
+ style: ToggleStyle::default(),
disabled: false,
- on_click: None,
+ placeholder: false,
filled: false,
- style: ToggleStyle::default(),
- tooltip: None,
+ visualization: false,
label: None,
label_size: LabelSize::Default,
label_color: Color::Muted,
- placeholder: false,
+ tooltip: None,
+ on_click: None,
}
}
@@ -110,6 +112,13 @@ impl Checkbox {
self
}
+ /// Makes the checkbox look enabled but without pointer cursor and hover styles.
+ /// Primarily used for uninteractive markdown previews.
+ pub fn visualization_only(mut self, visualization: bool) -> Self {
+ self.visualization = visualization;
+ self
+ }
+
/// Sets the style of the checkbox using the specified [`ToggleStyle`].
pub fn style(mut self, style: ToggleStyle) -> Self {
self.style = style;
@@ -209,11 +218,10 @@ impl RenderOnce for Checkbox {
let size = Self::container_size();
let checkbox = h_flex()
+ .group(group_id.clone())
.id(self.id.clone())
- .justify_center()
- .items_center()
.size(size)
- .group(group_id.clone())
+ .justify_center()
.child(
div()
.flex()
@@ -230,7 +238,7 @@ impl RenderOnce for Checkbox {
.when(self.disabled, |this| {
this.bg(cx.theme().colors().element_disabled.opacity(0.6))
})
- .when(!self.disabled, |this| {
+ .when(!self.disabled && !self.visualization, |this| {
this.group_hover(group_id.clone(), |el| el.border_color(hover_border_color))
})
.when(self.placeholder, |this| {
@@ -250,20 +258,14 @@ impl RenderOnce for Checkbox {
.map(|this| {
if self.disabled {
this.cursor_not_allowed()
+ } else if self.visualization {
+ this.cursor_default()
} else {
this.cursor_pointer()
}
})
.gap(DynamicSpacing::Base06.rems(cx))
.child(checkbox)
- .when_some(
- self.on_click.filter(|_| !self.disabled),
- |this, on_click| {
- this.on_click(move |click, window, cx| {
- on_click(&self.toggle_state.inverse(), click, window, cx)
- })
- },
- )
.when_some(self.label, |this, label| {
this.child(
Label::new(label)
@@ -274,6 +276,14 @@ impl RenderOnce for Checkbox {
.when_some(self.tooltip, |this, tooltip| {
this.tooltip(move |window, cx| tooltip(window, cx))
})
+ .when_some(
+ self.on_click.filter(|_| !self.disabled),
+ |this, on_click| {
+ this.on_click(move |click, window, cx| {
+ on_click(&self.toggle_state.inverse(), click, window, cx)
+ })
+ },
+ )
}
}
@@ -914,6 +924,15 @@ impl Component for Checkbox {
.into_any_element(),
)],
),
+ example_group_with_title(
+ "Extra",
+ vec![single_example(
+ "Visualization-Only",
+ Checkbox::new("viz_only", ToggleState::Selected)
+ .visualization_only(true)
+ .into_any_element(),
+ )],
+ ),
])
.into_any_element(),
)