diff --git a/crates/typst-html/src/convert.rs b/crates/typst-html/src/convert.rs index 208ea3dd3..65a4dabab 100644 --- a/crates/typst-html/src/convert.rs +++ b/crates/typst-html/src/convert.rs @@ -3,13 +3,12 @@ use typst_library::diag::{SourceResult, warning}; use typst_library::engine::Engine; use typst_library::foundations::{Content, StyleChain, Target, TargetElem}; use typst_library::introspection::{SplitLocator, TagElem}; -use typst_library::layout::{Abs, Axes, BlockBody, BlockElem, BoxElem, Region, Size}; -use typst_library::model::ParElem; +use typst_library::layout::{Abs, Axes, Region, Size}; use typst_library::routines::Pair; use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem}; 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. pub fn convert_to_nodes<'a>( @@ -46,44 +45,6 @@ fn handle( span: elem.span(), }; output.push(element.into()); - } else if let Some(elem) = child.to_packed::() { - 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::() { - // 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::() - .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::() { output.push(HtmlNode::text(' ', child.span())); } else if let Some(elem) = child.to_packed::() { diff --git a/crates/typst-html/src/rules.rs b/crates/typst-html/src/rules.rs index 472e155b0..c30e8bd5f 100644 --- a/crates/typst-html/src/rules.rs +++ b/crates/typst-html/src/rules.rs @@ -1,17 +1,17 @@ use std::num::NonZeroUsize; use ecow::{EcoVec, eco_format}; -use typst_library::diag::{At, warning}; +use typst_library::diag::{At, bail, warning}; use typst_library::foundations::{ Content, NativeElement, NativeRuleMap, ShowFn, Smart, StyleChain, Target, }; use typst_library::introspection::{Counter, Locator}; 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::{ Attribution, CiteElem, CiteGroup, Destination, EmphElem, EnumElem, FigureCaption, - FigureElem, HeadingElem, LinkElem, LinkTarget, ListElem, ParbreakElem, QuoteElem, - RefElem, StrongElem, TableCell, TableElem, TermsElem, TitleElem, + FigureElem, HeadingElem, LinkElem, LinkTarget, ListElem, ParElem, ParbreakElem, + QuoteElem, RefElem, StrongElem, TableCell, TableElem, TermsElem, TitleElem, }; use typst_library::text::{ HighlightElem, LinebreakElem, OverlineElem, RawElem, RawLine, SmallcapsElem, @@ -26,6 +26,7 @@ pub fn register(rules: &mut NativeRuleMap) { use Target::{Html, Paged}; // Model. + rules.register(Html, PAR_RULE); rules.register(Html, STRONG_RULE); rules.register(Html, EMPH_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_LINE_RULE); + // Layout. + rules.register(Html, BLOCK_RULE); + rules.register(Html, BOX_RULE); + // Visualize. rules.register(Html, IMAGE_RULE); @@ -61,6 +66,9 @@ pub fn register(rules: &mut NativeRuleMap) { rules.register::(Paged, |elem, _, _| Ok(elem.body.clone())); } +const PAR_RULE: ShowFn = + |elem, _, _| Ok(HtmlElem::new(tag::p).with_body(Some(elem.body.clone())).pack()); + const STRONG_RULE: ShowFn = |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 = |elem, _, _| Ok(elem.body.clone()); +// TODO: This is rather incomplete. +const BLOCK_RULE: ShowFn = |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 = |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 = |elem, engine, styles| { let image = elem.decode(engine, styles)?; diff --git a/tests/ref/html/box-html.html b/tests/ref/html/box-html.html index b2a26533b..7e860255b 100644 --- a/tests/ref/html/box-html.html +++ b/tests/ref/html/box-html.html @@ -5,6 +5,6 @@ -

Text Span.

+

Text Span.