typst_library/layout/
stack.rs

1use std::fmt::{self, Debug, Formatter};
2
3use crate::foundations::{Content, cast, elem};
4use crate::layout::{Dir, Spacing};
5
6/// Arranges content and spacing horizontally or vertically.
7///
8/// The stack places a list of items along an axis, with optional spacing
9/// between each item.
10///
11/// # Example
12/// ```example
13/// #stack(
14///   dir: ttb,
15///   rect(width: 40pt),
16///   rect(width: 120pt),
17///   rect(width: 90pt),
18/// )
19/// ```
20///
21/// # Accessibility
22/// Stacks do not carry any special semantics. The contents of the stack are
23/// read by Assistive Technology (AT) in the order in which they have been
24/// passed to this function.
25#[elem]
26pub struct StackElem {
27    /// The direction along which the items are stacked. Possible values are:
28    ///
29    /// - `{ltr}`: Left to right.
30    /// - `{rtl}`: Right to left.
31    /// - `{ttb}`: Top to bottom.
32    /// - `{btt}`: Bottom to top.
33    ///
34    /// You can use the `start` and `end` methods to obtain the initial and
35    /// final points (respectively) of a direction, as `alignment`. You can also
36    /// use the `axis` method to determine whether a direction is
37    /// `{"horizontal"}` or `{"vertical"}`. The `inv` method returns a
38    /// direction's inverse direction.
39    ///
40    /// For example, `{ttb.start()}` is `top`, `{ttb.end()}` is `bottom`,
41    /// `{ttb.axis()}` is `{"vertical"}` and `{ttb.inv()}` is equal to `btt`.
42    #[default(Dir::TTB)]
43    pub dir: Dir,
44
45    /// Spacing to insert between items where no explicit spacing was provided.
46    pub spacing: Option<Spacing>,
47
48    /// The children to stack along the axis.
49    #[variadic]
50    pub children: Vec<StackChild>,
51}
52
53/// A child of a stack element.
54#[derive(Clone, PartialEq, Hash)]
55pub enum StackChild {
56    /// Spacing between other children.
57    Spacing(Spacing),
58    /// Arbitrary block-level content.
59    Block(Content),
60}
61
62impl Debug for StackChild {
63    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
64        match self {
65            Self::Spacing(kind) => kind.fmt(f),
66            Self::Block(block) => block.fmt(f),
67        }
68    }
69}
70
71cast! {
72    StackChild,
73    self => match self {
74        Self::Spacing(spacing) => spacing.into_value(),
75        Self::Block(content) => content.into_value(),
76    },
77    v: Spacing => Self::Spacing(v),
78    v: Content => Self::Block(v),
79}