diff --git a/crates/typst/src/layout/place.rs b/crates/typst/src/layout/place.rs index 1a1fc7fd5..d15c97df3 100644 --- a/crates/typst/src/layout/place.rs +++ b/crates/typst/src/layout/place.rs @@ -1,26 +1,70 @@ use crate::foundations::{elem, scope, Cast, Content, Smart}; use crate::layout::{Alignment, Em, Length, Rel}; -/// Places content at an absolute position. +/// Places content relatively to its parent container. /// -/// Placed content will not affect the position of other content. Place is -/// always relative to its parent container and will be in the foreground of all -/// other content in the container. Page margins will be respected. +/// Placed content can be either overlaid (the default) or floating. Overlaid +/// content is aligned with the parent container according to the given +/// [`alignment`]($place.alignment), and shown over any other content added so +/// far in the container. Floating content is placed at the top or bottom of +/// the container, displacing other content down or up respectively. In both +/// cases, the content position can be adjusted with [`dx`]($place.dx) and +/// [`dy`]($place.dy) offsets without affecting the layout. /// +/// The parent can be any container such as a [`block`], [`box`], +/// [`rect`], etc. A top level `place` call will place content directly +/// in the text area of the current page. This can be used for absolute +/// positioning on the page: with a `top + left` +/// [`alignment`]($place.alignment), the offsets `dx` and `dy` will set the +/// position of the element's top left corner relatively to the top left corner +/// of the text area. For absolute positioning on the full page including +/// margins, you can use `place` in [`page.foreground`]($page.foreground) or +/// [`page.background`]($page.background). /// -/// # Example +/// # Examples /// ```example /// #set page(height: 60pt) /// Hello, world! /// +/// #rect( +/// width: 100%, +/// height: 2cm, +/// place(horizon + right, square()), +/// ) +/// /// #place( -/// top + right, -/// square( -/// width: 20pt, -/// stroke: 2pt + blue -/// ), +/// top + left, +/// dx: -5pt, +/// square(size: 5pt, fill: red), /// ) /// ``` +/// +/// # Effect on the position of other elements +/// +/// Overlaid elements don't take space in the flow of content, but a `place` +/// call inserts an invisible block-level element in the flow. This can +/// affect the layout by breaking the current paragraph. To avoid this, +/// you can wrap the `place` call in a [`box`] when the call is made +/// in the middle of a paragraph. The alignment and offsets will then be +/// relative to this zero-size box. To make sure it doesn't interfere with +/// spacing, the box should be attached to a word using a zero-width joiner. +/// +/// For example, the following defines a function for attaching an annotation +/// to the following word: +/// +/// ```example +/// #let annotate(..args) = { +/// box(place(..args)) +/// sym.zwj +/// h(0pt, weak: true) +/// } +/// +/// A placed #annotate(square(), dy: 2pt) +/// square in my text. +/// ``` +/// +/// The zero-width weak spacing serves to discard spaces between the function +/// call and the next word in markup. #[elem(scope)] pub struct PlaceElem { /// Relative to which position in the parent container to place the content. @@ -28,9 +72,8 @@ pub struct PlaceElem { /// - If `float` is `{false}`, then this can be any alignment other than `{auto}`. /// - If `float` is `{true}`, then this must be `{auto}`, `{top}`, or `{bottom}`. /// - /// When an axis of the page is `{auto}` sized, all alignments relative to - /// that axis will be ignored, instead, the item will be placed in the - /// origin of the axis. + /// When `float` is `{false}` and no vertical alignment is specified, the + /// content is placed at the current position on the vertical axis. #[positional] #[default(Smart::Custom(Alignment::START))] pub alignment: Smart, @@ -73,7 +116,8 @@ pub struct PlaceElem { /// ``` pub float: bool, - /// The amount of clearance the placed element has in a floating layout. + /// The spacing between the placed element and other elements in a floating + /// layout. /// /// Has no effect if `float` is `{false}`. #[default(Em::new(1.5).into())]