diff --git a/crates/typst-html/src/lib.rs b/crates/typst-html/src/lib.rs
index ffd8e2505..1fa6aa216 100644
--- a/crates/typst-html/src/lib.rs
+++ b/crates/typst-html/src/lib.rs
@@ -14,7 +14,7 @@ use typst_library::html::{
use typst_library::introspection::{
Introspector, Locator, LocatorLink, SplitLocator, TagElem,
};
-use typst_library::layout::{Abs, Axes, BoxElem, Region, Size};
+use typst_library::layout::{Abs, Axes, BlockBody, BlockElem, BoxElem, Region, Size};
use typst_library::model::{DocumentInfo, ParElem};
use typst_library::routines::{Arenas, Pair, RealizationKind, Routines};
use typst_library::text::{LinebreakElem, SmartQuoteElem, SpaceElem, TextElem};
@@ -197,13 +197,34 @@ fn handle(
.into(),
);
} else if let Some(elem) = child.to_packed::() {
- // FIXME: Very incomplete and hacky, but makes boxes kind fulfill their
- // purpose for now.
+ // TODO: This is rather incomplete.
if let Some(body) = elem.body(styles) {
let children =
html_fragment(engine, body, locator.next(&elem.span()), styles)?;
- output.extend(children);
+ 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(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-library/src/html/dom.rs b/crates/typst-library/src/html/dom.rs
index 5b6eab4d6..2acd839dd 100644
--- a/crates/typst-library/src/html/dom.rs
+++ b/crates/typst-library/src/html/dom.rs
@@ -210,7 +210,10 @@ impl HtmlAttr {
/// Creates a compile-time constant `HtmlAttr`.
///
- /// Should only be used in const contexts because it can panic.
+ /// Must only be used in const contexts (in a constant definition or
+ /// explicit `const { .. }` block) because otherwise a panic for a malformed
+ /// attribute or not auto-internible constant will only be caught at
+ /// runtime.
#[track_caller]
pub const fn constant(string: &'static str) -> Self {
if string.is_empty() {
@@ -605,6 +608,7 @@ pub mod tag {
/// Predefined constants for HTML attributes.
///
/// Note: These are very incomplete.
+#[allow(non_upper_case_globals)]
pub mod attr {
use super::HtmlAttr;
@@ -619,13 +623,18 @@ pub mod attr {
attrs! {
charset
+ cite
+ colspan
content
href
name
- value
+ reversed
role
+ rowspan
+ start
+ style
+ value
}
- #[allow(non_upper_case_globals)]
pub const aria_level: HtmlAttr = HtmlAttr::constant("aria-level");
}
diff --git a/crates/typst-library/src/model/enum.rs b/crates/typst-library/src/model/enum.rs
index 2d774cbbb..4dc834ab7 100644
--- a/crates/typst-library/src/model/enum.rs
+++ b/crates/typst-library/src/model/enum.rs
@@ -9,7 +9,7 @@ use crate::foundations::{
cast, elem, scope, Array, Content, NativeElement, Packed, Show, Smart, StyleChain,
Styles, TargetElem,
};
-use crate::html::{attr, tag, HtmlAttr, HtmlElem};
+use crate::html::{attr, tag, HtmlElem};
use crate::layout::{Alignment, BlockElem, Em, HAlignment, Length, VAlignment, VElem};
use crate::model::{ListItemLike, ListLike, Numbering, NumberingPattern, ParElem};
@@ -229,10 +229,10 @@ impl Show for Packed {
if TargetElem::target_in(styles).is_html() {
let mut elem = HtmlElem::new(tag::ol);
if self.reversed(styles) {
- elem = elem.with_attr(HtmlAttr::constant("reversed"), "reversed");
+ elem = elem.with_attr(attr::reversed, "reversed");
}
if let Some(n) = self.start(styles).custom() {
- elem = elem.with_attr(HtmlAttr::constant("start"), eco_format!("{n}"));
+ elem = elem.with_attr(attr::start, eco_format!("{n}"));
}
let body = Content::sequence(self.children.iter().map(|item| {
let mut li = HtmlElem::new(tag::li);
diff --git a/crates/typst-library/src/model/quote.rs b/crates/typst-library/src/model/quote.rs
index 774384acb..79e9b4e36 100644
--- a/crates/typst-library/src/model/quote.rs
+++ b/crates/typst-library/src/model/quote.rs
@@ -4,7 +4,7 @@ use crate::foundations::{
cast, elem, Content, Depth, Label, NativeElement, Packed, Show, ShowSet, Smart,
StyleChain, Styles, TargetElem,
};
-use crate::html::{tag, HtmlAttr, HtmlElem};
+use crate::html::{attr, tag, HtmlElem};
use crate::introspection::Locatable;
use crate::layout::{
Alignment, BlockBody, BlockElem, Em, HElem, PadElem, Spacing, VElem,
@@ -194,10 +194,7 @@ impl Show for Packed {
if let Some(Attribution::Content(attribution)) = attribution {
if let Some(link) = attribution.to_packed::() {
if let LinkTarget::Dest(Destination::Url(url)) = &link.dest {
- elem = elem.with_attr(
- HtmlAttr::constant("cite"),
- url.clone().into_inner(),
- );
+ elem = elem.with_attr(attr::cite, url.clone().into_inner());
}
}
}
diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs
index ba7924422..82c1cc08b 100644
--- a/crates/typst-library/src/model/table.rs
+++ b/crates/typst-library/src/model/table.rs
@@ -9,7 +9,7 @@ use crate::foundations::{
cast, elem, scope, Content, NativeElement, Packed, Show, Smart, StyleChain,
TargetElem,
};
-use crate::html::{tag, HtmlAttr, HtmlAttrs, HtmlElem, HtmlTag};
+use crate::html::{attr, tag, HtmlAttrs, HtmlElem, HtmlTag};
use crate::introspection::Locator;
use crate::layout::grid::resolve::{table_to_cellgrid, Cell, CellGrid, Entry};
use crate::layout::{
@@ -268,10 +268,10 @@ fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content {
let mut attrs = HtmlAttrs::default();
let span = |n: NonZeroUsize| (n != NonZeroUsize::MIN).then(|| n.to_string());
if let Some(colspan) = span(cell.colspan(styles)) {
- attrs.push(HtmlAttr::constant("colspan"), colspan);
+ attrs.push(attr::colspan, colspan);
}
if let Some(rowspan) = span(cell.rowspan(styles)) {
- attrs.push(HtmlAttr::constant("rowspan"), rowspan);
+ attrs.push(attr::rowspan, rowspan);
}
HtmlElem::new(tag)
.with_body(Some(cell.body.clone()))
diff --git a/tests/ref/html/block-html.html b/tests/ref/html/block-html.html
new file mode 100644
index 000000000..98d971b88
--- /dev/null
+++ b/tests/ref/html/block-html.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+ Paragraph
+
+
+ Div
+
+
+
diff --git a/tests/ref/html/box-html.html b/tests/ref/html/box-html.html
new file mode 100644
index 000000000..5c970a6bc
--- /dev/null
+++ b/tests/ref/html/box-html.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+ Text Span.
+
+
+
diff --git a/tests/suite/layout/container.typ b/tests/suite/layout/container.typ
index bb53a0411..f15ddfe4a 100644
--- a/tests/suite/layout/container.typ
+++ b/tests/suite/layout/container.typ
@@ -264,6 +264,13 @@ First!
image("/assets/images/rhino.png", width: 30pt)
)
+--- box-html html ---
+Text #box[Span].
+
+--- block-html html ---
+Paragraph
+#block[Div]
+
--- container-layoutable-child ---
// Test box/block sizing with directly layoutable child.
//