Move par, box, and block to show rules in HTML export (#6709)

This commit is contained in:
Laurenz 2025-08-06 12:30:49 +02:00 committed by GitHub
parent 15d5591a42
commit cfce90ec29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 41 additions and 46 deletions

View File

@ -3,13 +3,12 @@ use typst_library::diag::{SourceResult, warning};
use typst_library::engine::Engine; use typst_library::engine::Engine;
use typst_library::foundations::{Content, StyleChain, Target, TargetElem}; use typst_library::foundations::{Content, StyleChain, Target, TargetElem};
use typst_library::introspection::{SplitLocator, TagElem}; use typst_library::introspection::{SplitLocator, TagElem};
use typst_library::layout::{Abs, Axes, BlockBody, BlockElem, BoxElem, Region, Size}; use typst_library::layout::{Abs, Axes, Region, Size};
use typst_library::model::ParElem;
use typst_library::routines::Pair; use typst_library::routines::Pair;
use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem}; use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem};
use crate::fragment::html_fragment; use crate::fragment::html_fragment;
use crate::{FrameElem, HtmlElem, HtmlElement, HtmlFrame, HtmlNode, attr, tag}; use crate::{FrameElem, HtmlElem, HtmlElement, HtmlFrame, HtmlNode, tag};
/// Converts realized content into HTML nodes. /// Converts realized content into HTML nodes.
pub fn convert_to_nodes<'a>( pub fn convert_to_nodes<'a>(
@ -46,44 +45,6 @@ fn handle(
span: elem.span(), span: elem.span(),
}; };
output.push(element.into()); output.push(element.into());
} else if let Some(elem) = child.to_packed::<ParElem>() {
let children =
html_fragment(engine, &elem.body, locator.next(&elem.span()), styles)?;
output.push(
HtmlElement::new(tag::p)
.with_children(children)
.spanned(elem.span())
.into(),
);
} else if let Some(elem) = child.to_packed::<BoxElem>() {
// TODO: This is rather incomplete.
if let Some(body) = elem.body.get_ref(styles) {
let children =
html_fragment(engine, body, locator.next(&elem.span()), styles)?;
output.push(
HtmlElement::new(tag::span)
.with_attr(attr::style, "display: inline-block;")
.with_children(children)
.spanned(elem.span())
.into(),
)
}
} else if let Some((elem, body)) =
child
.to_packed::<BlockElem>()
.and_then(|elem| match elem.body.get_ref(styles) {
Some(BlockBody::Content(body)) => Some((elem, body)),
_ => None,
})
{
// TODO: This is rather incomplete.
let children = html_fragment(engine, body, locator.next(&elem.span()), styles)?;
output.push(
HtmlElement::new(tag::div)
.with_children(children)
.spanned(elem.span())
.into(),
);
} else if child.is::<SpaceElem>() { } else if child.is::<SpaceElem>() {
output.push(HtmlNode::text(' ', child.span())); output.push(HtmlNode::text(' ', child.span()));
} else if let Some(elem) = child.to_packed::<TextElem>() { } else if let Some(elem) = child.to_packed::<TextElem>() {

View File

@ -1,17 +1,17 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use ecow::{EcoVec, eco_format}; use ecow::{EcoVec, eco_format};
use typst_library::diag::{At, warning}; use typst_library::diag::{At, bail, warning};
use typst_library::foundations::{ use typst_library::foundations::{
Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target, Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target,
}; };
use typst_library::introspection::{Counter, Locator}; use typst_library::introspection::{Counter, Locator};
use typst_library::layout::resolve::{Cell, CellGrid, Entry, table_to_cellgrid}; use typst_library::layout::resolve::{Cell, CellGrid, Entry, table_to_cellgrid};
use typst_library::layout::{OuterVAlignment, Sizing}; use typst_library::layout::{BlockBody, BlockElem, BoxElem, OuterVAlignment, Sizing};
use typst_library::model::{ use typst_library::model::{
Attribution, CiteElem, CiteGroup, Destination, EmphElem, EnumElem, FigureCaption, Attribution, CiteElem, CiteGroup, Destination, EmphElem, EnumElem, FigureCaption,
FigureElem, HeadingElem, LinkElem, LinkTarget, ListElem, ParbreakElem, QuoteElem, FigureElem, HeadingElem, LinkElem, LinkTarget, ListElem, ParElem, ParbreakElem,
RefElem, StrongElem, TableCell, TableElem, TermsElem, TitleElem, QuoteElem, RefElem, StrongElem, TableCell, TableElem, TermsElem, TitleElem,
}; };
use typst_library::text::{ use typst_library::text::{
HighlightElem, LinebreakElem, OverlineElem, RawElem, RawLine, SmallcapsElem, HighlightElem, LinebreakElem, OverlineElem, RawElem, RawLine, SmallcapsElem,
@ -26,6 +26,7 @@ pub fn register(rules: &mut NativeRuleMap) {
use Target::{Html, Paged}; use Target::{Html, Paged};
// Model. // Model.
rules.register(Html, PAR_RULE);
rules.register(Html, STRONG_RULE); rules.register(Html, STRONG_RULE);
rules.register(Html, EMPH_RULE); rules.register(Html, EMPH_RULE);
rules.register(Html, LIST_RULE); rules.register(Html, LIST_RULE);
@ -52,6 +53,10 @@ pub fn register(rules: &mut NativeRuleMap) {
rules.register(Html, RAW_RULE); rules.register(Html, RAW_RULE);
rules.register(Html, RAW_LINE_RULE); rules.register(Html, RAW_LINE_RULE);
// Layout.
rules.register(Html, BLOCK_RULE);
rules.register(Html, BOX_RULE);
// Visualize. // Visualize.
rules.register(Html, IMAGE_RULE); rules.register(Html, IMAGE_RULE);
@ -61,6 +66,9 @@ pub fn register(rules: &mut NativeRuleMap) {
rules.register::<FrameElem>(Paged, |elem, _, _| Ok(elem.body.clone())); rules.register::<FrameElem>(Paged, |elem, _, _| Ok(elem.body.clone()));
} }
const PAR_RULE: ShowFn<ParElem> =
|elem, _, _| Ok(HtmlElem::new(tag::p).with_body(Some(elem.body.clone())).pack());
const STRONG_RULE: ShowFn<StrongElem> = const STRONG_RULE: ShowFn<StrongElem> =
|elem, _, _| Ok(HtmlElem::new(tag::strong).with_body(Some(elem.body.clone())).pack()); |elem, _, _| Ok(HtmlElem::new(tag::strong).with_body(Some(elem.body.clone())).pack());
@ -454,6 +462,32 @@ pub fn html_span_filled(content: Content, color: Color) -> Content {
const RAW_LINE_RULE: ShowFn<RawLine> = |elem, _, _| Ok(elem.body.clone()); const RAW_LINE_RULE: ShowFn<RawLine> = |elem, _, _| Ok(elem.body.clone());
// TODO: This is rather incomplete.
const BLOCK_RULE: ShowFn<BlockElem> = |elem, _, styles| {
let body = match elem.body.get_cloned(styles) {
None => None,
Some(BlockBody::Content(body)) => Some(body),
// These are only generated by native `typst-layout` show rules.
Some(BlockBody::SingleLayouter(_) | BlockBody::MultiLayouter(_)) => {
bail!(
elem.span(),
"blocks with layout routines should not occur in \
HTML export this is a bug"
)
}
};
Ok(HtmlElem::new(tag::div).with_body(body).pack())
};
// TODO: This is rather incomplete.
const BOX_RULE: ShowFn<BoxElem> = |elem, _, styles| {
Ok(HtmlElem::new(tag::span)
.with_styles(css::Properties::new().with("display", "inline-block"))
.with_body(elem.body.get_cloned(styles))
.pack())
};
const IMAGE_RULE: ShowFn<ImageElem> = |elem, engine, styles| { const IMAGE_RULE: ShowFn<ImageElem> = |elem, engine, styles| {
let image = elem.decode(engine, styles)?; let image = elem.decode(engine, styles)?;

View File

@ -5,6 +5,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>
<body> <body>
<p>Text <span style="display: inline-block;">Span</span>.</p> <p>Text <span style="display: inline-block">Span</span>.</p>
</body> </body>
</html> </html>