Merge branch 'master' into feature/test-recorder

This commit is contained in:
Héctor Ramón Jiménez 2025-07-08 00:29:55 +02:00
commit 98d8f466bb
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
98 changed files with 643 additions and 204 deletions

View file

@ -400,9 +400,9 @@ where
Renderer: core::Renderer + 'a,
{
fn from(
column: Container<'a, Message, Theme, Renderer>,
container: Container<'a, Message, Theme, Renderer>,
) -> Element<'a, Message, Theme, Renderer> {
Element::new(column)
Element::new(container)
}
}

View file

@ -50,7 +50,10 @@ use crate::core::theme;
use crate::core::{
self, Color, Element, Length, Padding, Pixels, Theme, color,
};
use crate::{column, container, rich_text, row, scrollable, span, text};
use crate::{
column, container, horizontal_rule, rich_text, row, rule, scrollable, span,
text, vertical_rule,
};
use std::borrow::BorrowMut;
use std::cell::{Cell, RefCell};
@ -208,6 +211,10 @@ pub enum Item {
/// The alternative text of the image.
alt: Text,
},
/// A quote.
Quote(Vec<Item>),
/// A horizontal separator.
Rule,
}
/// A bunch of parsed Markdown text.
@ -339,8 +346,8 @@ impl Span {
///
/// fn view(&self) -> Element<'_, Message> {
/// markdown::view(&self.markdown, Theme::TokyoNight)
/// .map(Message::LinkClicked)
/// .into()
/// .map(Message::LinkClicked)
/// .into()
/// }
///
/// fn update(state: &mut State, message: Message) {
@ -454,6 +461,7 @@ fn parse_with<'a>(
) -> impl Iterator<Item = (Item, &'a str, HashSet<String>)> + 'a {
enum Scope {
List(List),
Quote(Vec<Item>),
}
struct List {
@ -524,6 +532,9 @@ fn parse_with<'a>(
Scope::List(list) => {
list.items.last_mut().expect("item context").push(item);
}
Scope::Quote(items) => {
items.push(item);
}
}
None
@ -605,6 +616,22 @@ fn parse_with<'a>(
None
}
pulldown_cmark::Tag::BlockQuote(_kind) if !metadata && !table => {
let prev = if spans.is_empty() {
None
} else {
produce(
state.borrow_mut(),
&mut stack,
Item::Paragraph(Text::new(spans.drain(..).collect())),
source,
)
};
stack.push(Scope::Quote(Vec::new()));
prev
}
pulldown_cmark::Tag::CodeBlock(
pulldown_cmark::CodeBlockKind::Fenced(language),
) if !metadata && !table => {
@ -703,7 +730,9 @@ fn parse_with<'a>(
pulldown_cmark::TagEnd::List(_) if !metadata && !table => {
let scope = stack.pop()?;
let Scope::List(list) = scope;
let Scope::List(list) = scope else {
return None;
};
produce(
state.borrow_mut(),
@ -715,6 +744,22 @@ fn parse_with<'a>(
source,
)
}
pulldown_cmark::TagEnd::BlockQuote(_kind)
if !metadata && !table =>
{
let scope = stack.pop()?;
let Scope::Quote(quote) = scope else {
return None;
};
produce(
state.borrow_mut(),
&mut stack,
Item::Quote(quote),
source,
)
}
pulldown_cmark::TagEnd::Image if !metadata && !table => {
let (url, title) = image.take()?;
let alt = Text::new(spans.drain(..).collect());
@ -834,6 +879,9 @@ fn parse_with<'a>(
});
None
}
pulldown_cmark::Event::Rule => {
produce(state.borrow_mut(), &mut stack, Item::Rule, source)
}
_ => None,
})
}
@ -1063,6 +1111,8 @@ where
start: Some(start),
items,
} => viewer.ordered_list(settings, *start, items),
Item::Quote(quote) => viewer.quote(settings, quote),
Item::Rule => viewer.rule(settings),
}
}
@ -1226,7 +1276,44 @@ where
.into()
}
/// A view strategy to display a Markdown [`Item`].j
/// Displays a quote using the default look.
pub fn quote<'a, Message, Theme, Renderer>(
viewer: &impl Viewer<'a, Message, Theme, Renderer>,
settings: Settings,
contents: &'a [Item],
) -> Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: Catalog + 'a,
Renderer: core::text::Renderer<Font = Font> + 'a,
{
row![
vertical_rule(4),
column(
contents
.iter()
.enumerate()
.map(|(i, content)| item(viewer, settings, content, i)),
)
.spacing(settings.spacing.0),
]
.height(Length::Shrink)
.spacing(settings.spacing.0)
.into()
}
/// Displays a rule using the default look.
pub fn rule<'a, Message, Theme, Renderer>()
-> Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: Catalog + 'a,
Renderer: core::text::Renderer<Font = Font> + 'a,
{
horizontal_rule(2).into()
}
/// A view strategy to display a Markdown [`Item`].
pub trait Viewer<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
where
Self: Sized + 'a,
@ -1321,6 +1408,27 @@ where
) -> Element<'a, Message, Theme, Renderer> {
ordered_list(self, settings, start, items)
}
/// Displays a quote.
///
/// By default, it calls [`quote`].
fn quote(
&self,
settings: Settings,
contents: &'a [Item],
) -> Element<'a, Message, Theme, Renderer> {
quote(self, settings, contents)
}
/// Displays a rule.
///
/// By default, it calls [`rule`](self::rule()).
fn rule(
&self,
_settings: Settings,
) -> Element<'a, Message, Theme, Renderer> {
rule()
}
}
#[derive(Debug, Clone, Copy)]
@ -1338,7 +1446,7 @@ where
/// The theme catalog of Markdown items.
pub trait Catalog:
container::Catalog + scrollable::Catalog + text::Catalog
container::Catalog + scrollable::Catalog + rule::Catalog + text::Catalog
{
/// The styling class of a Markdown code block.
fn code_block<'a>() -> <Self as container::Catalog>::Class<'a>;

View file

@ -297,11 +297,11 @@ where
}
fn drag_enabled(&self) -> bool {
self.internal
.maximized()
.is_none()
.then(|| self.on_drag.is_some())
.unwrap_or_default()
if self.internal.maximized().is_none() {
self.on_drag.is_some()
} else {
Default::default()
}
}
fn grid_interaction(

View file

@ -134,9 +134,7 @@ where
let style = theme.style(&self.class);
let bounds = if self.is_horizontal {
let line_y = (bounds.y + (bounds.height / 2.0)
- (style.width as f32 / 2.0))
.round();
let line_y = (bounds.y + (bounds.height / 2.0)).round();
let (offset, line_width) = style.fill_mode.fill(bounds.width);
let line_x = bounds.x + offset;
@ -145,12 +143,10 @@ where
x: line_x,
y: line_y,
width: line_width,
height: style.width as f32,
height: bounds.height,
}
} else {
let line_x = (bounds.x + (bounds.width / 2.0)
- (style.width as f32 / 2.0))
.round();
let line_x = (bounds.x + (bounds.width / 2.0)).round();
let (offset, line_height) = style.fill_mode.fill(bounds.height);
let line_y = bounds.y + offset;
@ -158,7 +154,7 @@ where
Rectangle {
x: line_x,
y: line_y,
width: style.width as f32,
width: bounds.width,
height: line_height,
}
};
@ -167,6 +163,7 @@ where
renderer::Quad {
bounds,
border: border::rounded(style.radius),
snap: style.snap,
..renderer::Quad::default()
},
style.color,
@ -191,12 +188,12 @@ where
pub struct Style {
/// The color of the rule.
pub color: Color,
/// The width (thickness) of the rule line.
pub width: u16,
/// The radius of the line corners.
pub radius: border::Radius,
/// The [`FillMode`] of the rule.
pub fill_mode: FillMode,
/// Whether the rule should be snapped to the pixel grid.
pub snap: bool,
}
/// The fill mode of a rule.
@ -298,8 +295,8 @@ pub fn default(theme: &Theme) -> Style {
Style {
color: palette.background.strong.color,
width: 1,
radius: 0.0.into(),
fill_mode: FillMode::Full,
snap: true,
}
}

View file

@ -438,7 +438,7 @@ where
},
|limits| {
let child_limits = layout::Limits::new(
Size::new(limits.min().width, limits.min().height),
limits.min(),
Size::new(
if self.direction.horizontal().is_some() {
f32::INFINITY