index/objects/typesetting/
typst.rs

1use std::rc::Rc;
2
3use typst::{foundations::Bytes, layout::Abs, text::Font};
4use typst_as_lib::TypstTemplate;
5use typst_svg::svg_merged;
6use wasm_bindgen::prelude::*;
7
8use crate::{objects::vector_object::VectorObjectBuilder, utils::font_face::FontFace};
9
10/// A Typst is a typesetting object that can be used to render math text with Typst.
11#[wasm_bindgen]
12pub struct Typst {
13    /// The source of the Typst object.
14    source: Rc<String>,
15}
16
17#[wasm_bindgen]
18impl Typst {
19    /// Creates a new Typst object from a source string.
20    #[wasm_bindgen(constructor, return_description = "A new Typst object.")]
21    pub fn new(
22        #[wasm_bindgen(param_description = "The source of the Typst object.")]
23        source: String,
24    ) -> Typst {
25        Typst { source: Rc::new(source) }
26    }
27    /// Returns the source of the Typst object.
28    #[wasm_bindgen(getter, return_description = "The source of the Typst object.")]
29    pub fn source(&self) -> String {
30        self.source.to_string()
31    }
32    /// Renders the Typst object to an SVG string.
33    #[wasm_bindgen(return_description = "The SVG string.")]
34    pub fn to_svg(
35        &self,
36        #[wasm_bindgen(param_description = "The font faces to use when rendering the Typst object.")]
37        font_faces: Option<Vec<FontFace>>
38    ) -> Result<String, JsError> {
39        let fonts = font_faces.unwrap_or(Vec::new())
40            .iter()
41            .map(|font_face| font_face.data())
42            .map(|font_data| Font::new(Bytes::new(font_data), 0))
43            .collect::<Vec<Option<Font>>>();
44        if fonts.iter().any(|font| font.is_none()) {
45            return Err(JsError::new("Failed to load font."));
46        }
47        let fonts = fonts.into_iter().map(|font| font.unwrap()).collect::<Vec<Font>>();
48        let template = TypstTemplate::new(self.source()).add_fonts(fonts);
49        let doc = template
50            .compile()
51            .output
52            .map_err(|_| JsError::new("Failed to render Typst object."))?;
53        let padding = Abs::zero();
54        let svg = svg_merged(&doc, padding);
55        Ok(svg)
56    }
57    /// Renders the Typst object to a VectorObjectBuilder.
58    #[wasm_bindgen(return_description = "A VectorObjectBuilder representing the typesetting object.")]
59    pub fn vector_object_builder(
60        &self,
61        #[wasm_bindgen(param_description = "The FontFaces to use when rendering the Typst object, if any.")]
62        font_faces: Option<Vec<FontFace>>,
63    ) -> Result<VectorObjectBuilder, JsError> {
64        let svg = self.to_svg(font_faces.clone())?;
65        let builder = VectorObjectBuilder::from_svg(svg, font_faces, None);
66        Ok(builder)
67    }
68}