text_view: Update Switch, Checkbox, Radio to let label method support TextView. (#649)
- Add `style` method to TextView. - Add `inline` method to TextView to use default inline style.
This commit is contained in:
parent
9dade704fb
commit
8fa210bc21
10 changed files with 213 additions and 60 deletions
35
crates/story/examples/switch.rs
Normal file
35
crates/story/examples/switch.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use gpui::*;
|
||||||
|
use story::{Assets, SwitchStory};
|
||||||
|
|
||||||
|
pub struct Example {
|
||||||
|
story: Entity<SwitchStory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Example {
|
||||||
|
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
|
let story = SwitchStory::view(window, cx);
|
||||||
|
|
||||||
|
Self { story }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
|
||||||
|
cx.new(|cx| Self::new(window, cx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for Example {
|
||||||
|
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
div().p_4().size_full().child(self.story.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = Application::new().with_assets(Assets);
|
||||||
|
|
||||||
|
app.run(move |cx| {
|
||||||
|
story::init(cx);
|
||||||
|
cx.activate(true);
|
||||||
|
|
||||||
|
story::create_new_window("Switch Example", Example::view, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ use gpui_component::{
|
||||||
label::Label,
|
label::Label,
|
||||||
radio::{Radio, RadioGroup},
|
radio::{Radio, RadioGroup},
|
||||||
switch::Switch,
|
switch::Switch,
|
||||||
|
text::TextView,
|
||||||
v_flex, ActiveTheme, Disableable as _, Side, Sizable, StyledExt,
|
v_flex, ActiveTheme, Disableable as _, Side, Sizable, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -203,12 +204,18 @@ impl Render for SwitchStory {
|
||||||
v.check3 = !v.check3;
|
v.check3 = !v.check3;
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.child(div().w(px(300.)).child(
|
.child(
|
||||||
Checkbox::new("longlong-checkbox").label(
|
div().w(px(300.)).child(
|
||||||
"The long long label text, \
|
Checkbox::new("longlong-checkbox").label(
|
||||||
it should ellipsis when the text is too long.",
|
TextView::markdown(
|
||||||
|
"longlong-checkbox",
|
||||||
|
"The **long long label** text, \
|
||||||
|
it should ellipsis when the text is too long.",
|
||||||
|
)
|
||||||
|
.inline(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
use crate::{h_flex, v_flex, ActiveTheme, Disableable, IconName, Selectable};
|
use crate::{h_flex, text::Text, v_flex, ActiveTheme, Disableable, IconName, Selectable};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, relative, svg, App, ElementId, InteractiveElement,
|
div, prelude::FluentBuilder as _, px, relative, svg, App, ElementId, InteractiveElement,
|
||||||
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _,
|
IntoElement, ParentElement, RenderOnce, StatefulInteractiveElement as _, Styled as _, Window,
|
||||||
Styled as _, Window,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A Checkbox element.
|
/// A Checkbox element.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Checkbox {
|
pub struct Checkbox {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: Option<SharedString>,
|
label: Option<Text>,
|
||||||
checked: bool,
|
checked: bool,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
||||||
|
|
@ -26,7 +25,7 @@ impl Checkbox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
pub fn label(mut self, label: impl Into<Text>) -> Self {
|
||||||
self.label = Some(label.into());
|
self.label = Some(label.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{h_flex, v_flex, ActiveTheme, AxisExt, IconName};
|
use crate::{h_flex, text::Text, v_flex, ActiveTheme, AxisExt, IconName};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder, relative, svg, App, Axis, ElementId, InteractiveElement,
|
div, prelude::FluentBuilder, relative, svg, App, Axis, ElementId, InteractiveElement,
|
||||||
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled,
|
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled,
|
||||||
|
|
@ -13,7 +13,7 @@ use gpui::{
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Radio {
|
pub struct Radio {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
label: Option<SharedString>,
|
label: Option<Text>,
|
||||||
checked: bool,
|
checked: bool,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
||||||
|
|
@ -30,7 +30,7 @@ impl Radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
pub fn label(mut self, label: impl Into<Text>) -> Self {
|
||||||
self.label = Some(label.into());
|
self.label = Some(label.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
@ -114,24 +114,6 @@ impl RenderOnce for Radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static str> for Radio {
|
|
||||||
fn from(label: &'static str) -> Self {
|
|
||||||
Self::new(label).label(label)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SharedString> for Radio {
|
|
||||||
fn from(label: SharedString) -> Self {
|
|
||||||
Self::new(label.clone()).label(label)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Radio {
|
|
||||||
fn from(label: String) -> Self {
|
|
||||||
Self::new(SharedString::from(label.clone())).label(SharedString::from(label))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Radio group element.
|
/// A Radio group element.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct RadioGroup {
|
pub struct RadioGroup {
|
||||||
|
|
@ -200,6 +182,24 @@ impl RadioGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for Radio {
|
||||||
|
fn from(label: &'static str) -> Self {
|
||||||
|
Self::new(label).label(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SharedString> for Radio {
|
||||||
|
fn from(label: SharedString) -> Self {
|
||||||
|
Self::new(label.clone()).label(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Radio {
|
||||||
|
fn from(label: String) -> Self {
|
||||||
|
Self::new(SharedString::from(label.clone())).label(SharedString::from(label))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderOnce for RadioGroup {
|
impl RenderOnce for RadioGroup {
|
||||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||||
let on_change = self.on_change;
|
let on_change = self.on_change;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{h_flex, ActiveTheme, Disableable, Side, Sizable, Size};
|
use crate::{h_flex, text::Text, ActiveTheme, Disableable, Side, Sizable, Size};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, Animation, AnimationExt as _, AnyElement, App, Element,
|
div, prelude::FluentBuilder as _, px, Animation, AnimationExt as _, AnyElement, App, Element,
|
||||||
ElementId, GlobalElementId, InteractiveElement, IntoElement, LayoutId, ParentElement as _,
|
ElementId, GlobalElementId, InteractiveElement, IntoElement, LayoutId, ParentElement as _,
|
||||||
SharedString, Styled as _, Window,
|
Styled as _, Window,
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@ pub struct Switch {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
checked: bool,
|
checked: bool,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
label: Option<SharedString>,
|
label: Option<Text>,
|
||||||
label_side: Side,
|
label_side: Side,
|
||||||
on_click: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
|
on_click: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
|
@ -35,7 +35,7 @@ impl Switch {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
pub fn label(mut self, label: impl Into<Text>) -> Self {
|
||||||
self.label = Some(label.into());
|
self.label = Some(label.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ impl Element for Switch {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(self.label.clone(), |this, label| {
|
.when_some(self.label.take(), |this, label| {
|
||||||
this.child(div().child(label).map(|this| match self.size {
|
this.child(div().child(label).map(|this| match self.size {
|
||||||
Size::XSmall | Size::Small => this.text_sm(),
|
Size::XSmall | Size::Small => this.text_sm(),
|
||||||
_ => this.text_base(),
|
_ => this.text_base(),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use gpui::{
|
||||||
|
|
||||||
use crate::{h_flex, v_flex, ActiveTheme as _, Icon, IconName};
|
use crate::{h_flex, v_flex, ActiveTheme as _, Icon, IconName};
|
||||||
|
|
||||||
use super::utils::list_item_prefix;
|
use super::{utils::list_item_prefix, TextViewStyle};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
|
|
@ -172,8 +172,10 @@ impl Paragraph {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ref:
|
||||||
|
/// https://ui.shadcn.com/docs/components/typography
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Clone, IntoElement, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Node {
|
pub enum Node {
|
||||||
Root {
|
Root {
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
|
|
@ -317,7 +319,7 @@ impl RenderOnce for Paragraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ListState {
|
pub(crate) struct ListState {
|
||||||
todo: bool,
|
todo: bool,
|
||||||
ordered: bool,
|
ordered: bool,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
|
|
@ -328,6 +330,7 @@ impl Node {
|
||||||
item: Node,
|
item: Node,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
state: ListState,
|
state: ListState,
|
||||||
|
text_view_style: &TextViewStyle,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
|
|
@ -373,24 +376,26 @@ impl Node {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.child(child.render_node(
|
.child(child.render(
|
||||||
Some(ListState {
|
Some(ListState {
|
||||||
depth: state.depth + 1,
|
depth: state.depth + 1,
|
||||||
ordered: state.ordered,
|
ordered: state.ordered,
|
||||||
todo: checked.is_some(),
|
todo: checked.is_some(),
|
||||||
}),
|
}),
|
||||||
|
text_view_style,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Node::List { .. } => {
|
Node::List { .. } => {
|
||||||
items.push(div().ml(rems(1.)).child(child.render_node(
|
items.push(div().ml(rems(1.)).child(child.render(
|
||||||
Some(ListState {
|
Some(ListState {
|
||||||
depth: state.depth + 1,
|
depth: state.depth + 1,
|
||||||
ordered: state.ordered,
|
ordered: state.ordered,
|
||||||
todo: checked.is_some(),
|
todo: checked.is_some(),
|
||||||
}),
|
}),
|
||||||
|
text_view_style,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)))
|
)))
|
||||||
|
|
@ -477,17 +482,28 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_node(
|
pub(crate) fn render(
|
||||||
self,
|
self,
|
||||||
list_state: Option<ListState>,
|
list_state: Option<ListState>,
|
||||||
|
text_view_style: &TextViewStyle,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
let in_list = list_state.is_some();
|
let in_list = list_state.is_some();
|
||||||
let mb = if in_list { rems(0.0) } else { rems(1.) };
|
let mb = if in_list {
|
||||||
|
rems(0.)
|
||||||
|
} else {
|
||||||
|
text_view_style.paragraph_gap
|
||||||
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Node::Root { children } => div().children(children).into_any_element(),
|
Node::Root { children } => div()
|
||||||
|
.children(
|
||||||
|
children
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| c.render(None, text_view_style, window, cx)),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
Node::Paragraph(paragraph) => div().mb(mb).child(paragraph).into_any_element(),
|
Node::Paragraph(paragraph) => div().mb(mb).child(paragraph).into_any_element(),
|
||||||
Node::Heading { level, children } => {
|
Node::Heading { level, children } => {
|
||||||
let (text_size, font_weight) = match level {
|
let (text_size, font_weight) = match level {
|
||||||
|
|
@ -535,6 +551,7 @@ impl Node {
|
||||||
todo: list_state.todo,
|
todo: list_state.todo,
|
||||||
depth: list_state.depth,
|
depth: list_state.depth,
|
||||||
},
|
},
|
||||||
|
text_view_style,
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
));
|
));
|
||||||
|
|
@ -573,11 +590,3 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ref:
|
|
||||||
/// https://ui.shadcn.com/docs/components/typography
|
|
||||||
impl RenderOnce for Node {
|
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
||||||
self.render_node(None, window, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use crate::v_flex;
|
||||||
use super::element::{
|
use super::element::{
|
||||||
self, ImageNode, InlineTextStyle, LinkMark, Paragraph, Table, TableRow, TextNode,
|
self, ImageNode, InlineTextStyle, LinkMark, Paragraph, Table, TableRow, TextNode,
|
||||||
};
|
};
|
||||||
|
use super::TextViewStyle;
|
||||||
|
|
||||||
const BLOCK_ELEMENTS: [&str; 33] = [
|
const BLOCK_ELEMENTS: [&str; 33] = [
|
||||||
"html",
|
"html",
|
||||||
|
|
@ -78,9 +79,11 @@ pub(super) fn parse_html(source: &str) -> Result<element::Node, SharedString> {
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub(super) struct HtmlElement {
|
pub(super) struct HtmlElement {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
text: SharedString,
|
text: SharedString,
|
||||||
|
style: TextViewStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HtmlElement {
|
impl HtmlElement {
|
||||||
|
|
@ -88,6 +91,7 @@ impl HtmlElement {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
text: raw.into(),
|
text: raw.into(),
|
||||||
|
style: TextViewStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,6 +100,12 @@ impl HtmlElement {
|
||||||
self.text = raw.into();
|
self.text = raw.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set TextViewStyle.
|
||||||
|
pub(crate) fn style(mut self, style: impl Into<TextViewStyle>) -> Self {
|
||||||
|
self.style = style.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -150,7 +160,7 @@ impl Element for HtmlElement {
|
||||||
|
|
||||||
let mut el = div()
|
let mut el = div()
|
||||||
.map(|this| match root {
|
.map(|this| match root {
|
||||||
Ok(node) => this.child(node),
|
Ok(node) => this.child(node.render(None, &self.style, window, cx)),
|
||||||
Err(err) => this.child(
|
Err(err) => this.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use crate::v_flex;
|
||||||
use super::{
|
use super::{
|
||||||
element::{self, ImageNode, InlineTextStyle, LinkMark, Paragraph, Span, Table, TableRow},
|
element::{self, ImageNode, InlineTextStyle, LinkMark, Paragraph, Span, Table, TableRow},
|
||||||
html::parse_html,
|
html::parse_html,
|
||||||
|
TextViewStyle,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Markdown GFM renderer
|
/// Markdown GFM renderer
|
||||||
|
|
@ -30,9 +31,11 @@ use super::{
|
||||||
/// - As a markdown editor.
|
/// - As a markdown editor.
|
||||||
/// - Add custom markdown syntax.
|
/// - Add custom markdown syntax.
|
||||||
/// - Complex styles cumstomization.
|
/// - Complex styles cumstomization.
|
||||||
|
#[derive(Clone)]
|
||||||
pub(super) struct MarkdownElement {
|
pub(super) struct MarkdownElement {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
text: SharedString,
|
text: SharedString,
|
||||||
|
style: TextViewStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MarkdownElement {
|
impl MarkdownElement {
|
||||||
|
|
@ -40,6 +43,7 @@ impl MarkdownElement {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
text: raw.into(),
|
text: raw.into(),
|
||||||
|
style: TextViewStyle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,6 +52,12 @@ impl MarkdownElement {
|
||||||
self.text = raw.into();
|
self.text = raw.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set TextViewStyle.
|
||||||
|
pub(crate) fn style(mut self, style: impl Into<TextViewStyle>) -> Self {
|
||||||
|
self.style = style.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -106,7 +116,7 @@ impl Element for MarkdownElement {
|
||||||
|
|
||||||
let mut el = div()
|
let mut el = div()
|
||||||
.map(|this| match root {
|
.map(|this| match root {
|
||||||
Ok(node) => this.child(node),
|
Ok(node) => this.child(node.render(None, &self.style, window, cx)),
|
||||||
Err(err) => this.child(
|
Err(err) => this.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use gpui::{App, ElementId, IntoElement, RenderOnce, SharedString, Window};
|
use gpui::{rems, App, ElementId, IntoElement, Rems, RenderOnce, SharedString, Window};
|
||||||
use html::HtmlElement;
|
use html::HtmlElement;
|
||||||
use markdown::MarkdownElement;
|
use markdown::MarkdownElement;
|
||||||
|
|
||||||
|
|
@ -7,9 +7,79 @@ mod html;
|
||||||
mod markdown;
|
mod markdown;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
#[derive(IntoElement, Clone)]
|
||||||
|
pub enum Text {
|
||||||
|
String(SharedString),
|
||||||
|
TextView(TextView),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SharedString> for Text {
|
||||||
|
fn from(s: SharedString) -> Self {
|
||||||
|
Self::String(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Text {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Self::String(SharedString::from(s.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Text {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self::String(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TextView> for Text {
|
||||||
|
fn from(e: TextView) -> Self {
|
||||||
|
Self::TextView(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderOnce for Text {
|
||||||
|
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
|
||||||
|
match self {
|
||||||
|
Self::String(s) => s.into_any_element(),
|
||||||
|
Self::TextView(e) => e.into_any_element(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TextViewStyle used to customize the style for [`TextView`].
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct TextViewStyle {
|
||||||
|
paragraph_gap: Rems,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TextViewStyle {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
paragraph_gap: rems(1.),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextViewStyle {
|
||||||
|
/// Default style for inline text.
|
||||||
|
///
|
||||||
|
/// This style has no paragraph gap.
|
||||||
|
pub fn inline() -> Self {
|
||||||
|
Self {
|
||||||
|
paragraph_gap: rems(0.),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set paragraph gap, default is 1 rem.
|
||||||
|
pub fn paragraph_gap(mut self, gap: Rems) -> Self {
|
||||||
|
self.paragraph_gap = gap;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A text view that can render Markdown or HTML.
|
/// A text view that can render Markdown or HTML.
|
||||||
#[allow(private_interfaces)]
|
#[allow(private_interfaces)]
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement, Clone)]
|
||||||
pub enum TextView {
|
pub enum TextView {
|
||||||
Markdown(MarkdownElement),
|
Markdown(MarkdownElement),
|
||||||
Html(HtmlElement),
|
Html(HtmlElement),
|
||||||
|
|
@ -33,6 +103,19 @@ impl TextView {
|
||||||
Self::Html(el) => Self::Html(el.text(raw)),
|
Self::Html(el) => Self::Html(el.text(raw)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set [`TextViewStyle`].
|
||||||
|
pub fn style(self, style: TextViewStyle) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Markdown(el) => Self::Markdown(el.style(style)),
|
||||||
|
Self::Html(el) => Self::Html(el.style(style)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set to use [`TextViewStyle::inline`].
|
||||||
|
pub fn inline(self) -> Self {
|
||||||
|
self.style(TextViewStyle::inline())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for TextView {
|
impl RenderOnce for TextView {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder, px, AnyElement, AnyView, App, AppContext, Context, IntoElement,
|
div, prelude::FluentBuilder, px, AnyElement, AnyView, App, AppContext, Context, IntoElement,
|
||||||
ParentElement, Render, SharedString, Styled, Window,
|
ParentElement, Render, Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ActiveTheme;
|
use crate::{text::Text, ActiveTheme};
|
||||||
|
|
||||||
pub struct Tooltip {
|
pub struct Tooltip {
|
||||||
text: SharedString,
|
text: Text,
|
||||||
element_builder: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyElement>>,
|
element_builder: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyElement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tooltip {
|
impl Tooltip {
|
||||||
pub fn new(text: impl Into<SharedString>, _: &mut Window, cx: &mut App) -> AnyView {
|
pub fn new(text: impl Into<Text>, _: &mut Window, cx: &mut App) -> AnyView {
|
||||||
cx.new(|_| Self {
|
cx.new(|_| Self {
|
||||||
text: text.into(),
|
text: text.into(),
|
||||||
element_builder: None,
|
element_builder: None,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue