typst_batch/html/frame.rs
1//! HTML frame wrapper.
2
3#[cfg(feature = "svg")]
4use super::HtmlDocument;
5
6/// A frame that should be rendered as SVG.
7///
8/// Frames contain typst-rendered content (math, images, plots, etc.)
9/// that needs to be embedded as inline SVG in HTML output.
10#[derive(Debug, Clone, Copy)]
11pub struct HtmlFrame<'a>(pub(crate) &'a typst_html::HtmlFrame);
12
13impl<'a> HtmlFrame<'a> {
14 /// Get the frame's ID, if any.
15 #[inline]
16 pub fn id(&self) -> Option<&str> {
17 self.0.id.as_deref()
18 }
19
20 // =========================================================================
21 // Measurement API - for inline SVG vertical alignment
22 // =========================================================================
23
24 /// Get the frame's size in points (width, height).
25 ///
26 /// Useful for calculating CSS dimensions or vertical alignment.
27 #[inline]
28 pub fn size(&self) -> (f64, f64) {
29 let s = self.0.inner.size();
30 (s.x.to_pt(), s.y.to_pt())
31 }
32
33 /// Get the frame's width in points.
34 #[inline]
35 pub fn width(&self) -> f64 {
36 self.0.inner.width().to_pt()
37 }
38
39 /// Get the frame's height in points.
40 #[inline]
41 pub fn height(&self) -> f64 {
42 self.0.inner.height().to_pt()
43 }
44
45 /// Get the frame's baseline offset from top in points.
46 ///
47 /// For inline math, you can use this to calculate `vertical-align`:
48 /// ```ignore
49 /// let shift = frame.height() - frame.baseline();
50 /// let css = format!("vertical-align: -{}pt", shift);
51 /// ```
52 #[inline]
53 pub fn baseline(&self) -> f64 {
54 self.0.inner.baseline().to_pt()
55 }
56
57 /// Get the text size (in points) where the frame was defined.
58 ///
59 /// Useful for converting pt to em units:
60 /// ```ignore
61 /// let shift_em = shift_pt / frame.text_size();
62 /// ```
63 #[inline]
64 pub fn text_size(&self) -> f64 {
65 self.0.text_size.to_pt()
66 }
67
68 /// Calculate the vertical-align offset in em units for inline display.
69 ///
70 /// Returns a negative value suitable for CSS `vertical-align`.
71 /// For baseline-aligned inline content like math formulas.
72 #[inline]
73 pub fn vertical_align_em(&self) -> f64 {
74 let shift = self.height() - self.baseline();
75 -shift / self.text_size()
76 }
77
78 // =========================================================================
79 // Rendering
80 // =========================================================================
81
82 /// Render this frame to an SVG string.
83 ///
84 /// The returned string is a complete `<svg>...</svg>` element
85 /// suitable for embedding in HTML.
86 ///
87 /// # Example
88 ///
89 /// ```ignore
90 /// let svg = frame.to_svg(&doc);
91 /// // svg contains: <svg class="typst-frame" style="..." viewBox="...">...</svg>
92 /// ```
93 ///
94 /// # Note
95 ///
96 /// This method requires the `svg` feature to be enabled.
97 #[cfg(feature = "svg")]
98 pub fn to_svg(&self, doc: &HtmlDocument) -> String {
99 doc.render_frame_svg(self)
100 }
101
102 /// Render this frame to an inline SVG string with vertical-align style.
103 ///
104 /// Convenient wrapper that applies the calculated `vertical-align` offset.
105 ///
106 /// # Example
107 ///
108 /// ```ignore
109 /// let html = frame.to_inline_svg(&doc);
110 /// // Returns: <span style="vertical-align: -0.5em"><svg ...></svg></span>
111 /// ```
112 #[cfg(feature = "svg")]
113 pub fn to_inline_svg(&self, doc: &HtmlDocument) -> String {
114 let svg = self.to_svg(doc);
115 let align = self.vertical_align_em();
116 format!(
117 r#"<span style="vertical-align: {:.4}em">{}</span>"#,
118 align, svg
119 )
120 }
121}
122