summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2024-03-09 17:42:11 +0100
committerGitHub <noreply@github.com>2024-03-09 16:42:11 +0000
commit15ac6c316610b5931e81a4dad2c5fd172f4ed944 (patch)
tree077dc64d46b382a07b4079aa0092d1e76e52c613
parent639a8d0dc01171130c84903b512c200c659bc537 (diff)
Spruce up table docs (#3593)
-rw-r--r--crates/typst/src/layout/grid/mod.rs357
-rw-r--r--crates/typst/src/model/table.rs274
2 files changed, 412 insertions, 219 deletions
diff --git a/crates/typst/src/layout/grid/mod.rs b/crates/typst/src/layout/grid/mod.rs
index b58b5054..dc16c3c3 100644
--- a/crates/typst/src/layout/grid/mod.rs
+++ b/crates/typst/src/layout/grid/mod.rs
@@ -36,9 +36,19 @@ use crate::visualize::{Paint, Stroke};
/// There are multiple sizing modes for columns and rows that can be used to
/// create complex layouts.
///
-/// The sizing of the grid is determined by the track sizes specified in the
-/// arguments. Because each of the sizing parameters accepts the same values, we
-/// will explain them just once, here. Each sizing argument accepts an array of
+/// While the grid and table elements work very similarly, they are intended for
+/// different use cases and carry different semantics. The grid element is
+/// intended for presentational and layout purposes, while the
+/// [`{table}`]($table) element is intended for, in broad terms, presenting
+/// multiple related data points. In the future, Typst will annotate its output
+/// such that screenreaders will annouce content in `table` as tabular while a
+/// grid's content will be announced no different than multiple content blocks
+/// in the document flow. Set and show rules on one of these elements do not
+/// affect the other.
+///
+/// A grid's sizing is determined by the track sizes specified in the arguments.
+/// Because each of the sizing parameters accepts the same values, we will
+/// explain them just once, here. Each sizing argument accepts an array of
/// individual track sizes. A track size is either:
///
/// - `{auto}`: The track will be sized to fit its contents. It will be at most
@@ -60,22 +70,10 @@ use crate::visualize::{Paint, Stroke};
/// instead of an array. For example, `columns:` `{3}` is equivalent to
/// `columns:` `{(auto, auto, auto)}`.
///
-/// # Styling the grid
-/// The grid's appearance can be customized through different parameters, such
-/// as `fill` to give all cells a background; `align` to change how cells are
-/// aligned; `inset` to optionally add internal padding to each cell; and
-/// `stroke` to optionally enable grid lines with a certain stroke.
-///
-/// If you need to override one of the above options for a single cell, you can
-/// use the [`grid.cell`]($grid.cell) element. Alternatively, if you need the
-/// appearance options to depend on a cell's position (column and row), you may
-/// specify a function to `fill` or `align` of the form
-/// `(column, row) => value`. You may also use a show rule on
-/// [`grid.cell`]($grid.cell) - see that element's examples or the examples
-/// below for more information.
-///
/// # Examples
-/// The example below demonstrates the different track sizing options.
+/// The example below demonstrates the different track sizing options. It also
+/// shows how you can use [`grid.cell`]($grid.cell) in to make an individual
+/// cell span two grid tracks.
///
/// ```example
/// // We use `rect` to emphasize the
@@ -94,8 +92,10 @@ use crate::visualize::{Paint, Stroke};
/// rect[1/3 of the remains],
/// rect[2/3 of the remains],
/// rect(height: 100%)[Fixed height],
-/// image("tiger.jpg", height: 100%),
-/// image("tiger.jpg", height: 100%),
+/// grid.cell(
+/// colspan: 2,
+/// image("tiger.jpg", width: 100%),
+/// ),
/// )
/// ```
///
@@ -110,60 +110,42 @@ use crate::visualize::{Paint, Stroke};
/// )
/// ```
///
-/// Additionally, you can use [`grid.cell`]($grid.cell) in various ways to
-/// not only style each cell based on its position and other fields, but also
-/// to determine the cell's preferential position in the table.
-///
-/// ```example
-/// #set page(width: auto)
-/// #show grid.cell: it => {
-/// if it.y == 0 {
-/// // The first row's text must be white and bold.
-/// set text(white)
-/// strong(it)
-/// } else {
-/// // For the second row and beyond, we will show the day number for each
-/// // cell.
-///
-/// // In general, a cell's index is given by cell.x + columns * cell.y.
-/// // Days start in the second grid row, so we subtract 1 row.
-/// // But the first day is day 1, not day 0, so we add 1.
-/// let day = it.x + 7 * (it.y - 1) + 1
-/// if day <= 31 {
-/// // Place the day's number at the top left of the cell.
-/// // Only if the day is valid for this month (not 32 or higher).
-/// place(top + left, dx: 2pt, dy: 2pt, text(8pt, red.darken(40%))[#day])
-/// }
-/// it
-/// }
-/// }
+/// # Styling the grid
+/// The grid's appearance can be customized through different parameters. These
+/// are the most important ones:
///
-/// #grid(
-/// fill: (x, y) => if y == 0 { gray.darken(50%) },
-/// columns: (30pt,) * 7,
-/// rows: (auto, 30pt),
-/// // Events will be written at the bottom of each day square.
-/// align: bottom,
-/// inset: 5pt,
-/// stroke: (thickness: 0.5pt, dash: "densely-dotted"),
+/// - [`fill`]($grid.fill) to give all cells a background
+/// - [`align`]($grid.align) to change how cells are aligned
+/// - [`inset`]($grid.inset) to optionally add internal padding to each cell
+/// - [`stroke`]($grid.stroke) to optionally enable grid lines with a certain
+/// stroke
///
-/// [Sun], [Mon], [Tue], [Wed], [Thu], [Fri], [Sat],
+/// If you need to override one of the above options for a single cell, you can
+/// use the [`grid.cell`]($grid.cell) element. Likewise, you can override
+/// individual grid lines with the [`grid.hline`]($grid.hline) and
+/// [`grid.vline`]($grid.vline) elements.
///
-/// // This event will occur on the first Friday (sixth column).
-/// grid.cell(x: 5, fill: yellow.darken(10%))[Call],
+/// Alternatively, if you need the appearance options to depend on a cell's
+/// position (column and row), you may specify a function to `fill` or `align`
+/// of the form `(column, row) => value`. You may also use a show rule on
+/// [`grid.cell`]($grid.cell) - see that element's examples or the examples
+/// below for more information.
///
-/// // This event will occur every Monday (second column).
-/// // We have to repeat it 5 times so it occurs every week.
-/// ..(grid.cell(x: 1, fill: red.lighten(50%))[Meet],) * 5,
+/// Locating most of your styling in set and show rules is recommended, as it
+/// keeps the grid's or table's actual usages clean and easy to read. It also
+/// allows you to easily change the grid's appearance in one place.
///
-/// // This event will occur at day 19.
-/// grid.cell(x: 4, y: 3, fill: orange.lighten(25%))[Talk],
+/// ## Stroke styling precedence
+/// There are three ways to set the stroke of a grid cell: through
+/// [`{grid.cell}`'s `stroke` field]($grid.cell.stroke), by using
+/// [`{grid.hline}`]($grid.hline) and [`{grid.vline}`]($grid.vline), or by
+/// setting the [`{grid}`'s `stroke` field]($grid.stroke). When multiple of
+/// these settings are present and conflict, the `hline` and `vline` settings
+/// take the highest precedence, followed by the `cell` settings, and finally
+/// the `grid` settings.
///
-/// // These events will occur at the second week, where available.
-/// grid.cell(y: 2, fill: aqua)[Chat],
-/// grid.cell(y: 2, fill: aqua)[Walk],
-/// )
-/// ```
+/// Furthermore, strokes of a repeated grid header or footer will take
+/// precedence over regular cell strokes.
#[elem(scope, LayoutMultiple)]
pub struct GridElem {
/// The column sizes.
@@ -209,13 +191,16 @@ pub struct GridElem {
///
/// ```example
/// #grid(
- /// fill: (col, row) => if calc.even(col + row) { luma(240) } else { white },
+ /// fill: (col, row) =>
+ /// if calc.even(col + row) { luma(230) }
+ /// else { white },
/// align: center + horizon,
/// columns: 4,
+ /// inset: 2pt,
/// [X], [O], [X], [O],
/// [O], [X], [O], [X],
/// [X], [O], [X], [O],
- /// [O], [X], [O], [X]
+ /// [O], [X], [O], [X],
/// )
/// ```
#[borrowed]
@@ -225,17 +210,11 @@ pub struct GridElem {
///
/// This can either be a single alignment, an array of alignments
/// (corresponding to each column) or a function that returns an alignment.
- /// The function is passed the cells' column and row index, starting at zero.
- /// If set to `{auto}`, the outer alignment is used.
+ /// The function is passed the cells' column and row index, starting at
+ /// zero. If set to `{auto}`, the outer alignment is used.
///
- /// ```example
- /// #grid(
- /// columns: 3,
- /// align: (x, y) => (left, center, right).at(x),
- /// [Hello], [Hello], [Hello],
- /// [A], [B], [C],
- /// )
- /// ```
+ /// You can find an example for this argument at the
+ /// [`table.align`]($table.align) parameter.
#[borrowed]
pub align: Celled<Smart<Alignment>>,
@@ -249,31 +228,81 @@ pub struct GridElem {
/// multiple specific cells, consider specifying one or more of
/// [`grid.hline`]($grid.hline) and [`grid.vline`]($grid.vline) alongside
/// your grid cells.
+ ///
+ /// ```example
+ /// #set page(height: 13em, width: 26em)
+ ///
+ /// #let cv(..jobs) = grid(
+ /// columns: 2,
+ /// inset: 5pt,
+ /// stroke: (x, y) => if x == 0 and y > 0 {
+ /// (right: (
+ /// paint: luma(180),
+ /// thickness: 1.5pt,
+ /// dash: "dotted"
+ /// ))
+ /// },
+ /// grid.header(grid.cell(colspan: 2)[
+ /// *Professional Experience*
+ /// #box(width: 1fr, line(length: 100%, stroke: luma(180)))
+ /// ]),
+ /// ..{
+ /// let last = none
+ /// for job in jobs.pos() {
+ /// (
+ /// if job.year != last [*#job.year*],
+ /// [
+ /// *#job.company* - #job.role _(#job.timeframe)_ \
+ /// #job.details
+ /// ]
+ /// )
+ /// last = job.year
+ /// }
+ /// }
+ /// )
+ ///
+ /// #cv(
+ /// (
+ /// year: 2012,
+ /// company: [Pear Seed & Co.],
+ /// role: [Lead Engineer],
+ /// timeframe: [Jul - Dec],
+ /// details: [
+ /// - Raised engineers from 3x to 10x
+ /// - Did a great job
+ /// ],
+ /// ),
+ /// (
+ /// year: 2012,
+ /// company: [Mega Corp.],
+ /// role: [VP of Sales],
+ /// timeframe: [Mar - Jun],
+ /// details: [- Closed tons of customers],
+ /// ),
+ /// (
+ /// year: 2013,
+ /// company: [Tiny Co.],
+ /// role: [CEO],
+ /// timeframe: [Jan - Dec],
+ /// details: [- Delivered 4x more shareholder value],
+ /// ),
+ /// (
+ /// year: 2014,
+ /// company: [Glorbocorp Ltd],
+ /// role: [CTO],
+ /// timeframe: [Jan - Mar],
+ /// details: [- Drove containerization forward],
+ /// ),
+ /// )
+ /// ```
#[resolve]
#[fold]
pub stroke: Celled<Sides<Option<Option<Arc<Stroke>>>>>,
/// How much to pad the cells' content.
///
- /// ```example
- /// #grid(
- /// inset: 10pt,
- /// fill: (_, row) => (red, blue).at(row),
- /// [Hello],
- /// [World],
- /// )
- ///
- /// #grid(
- /// columns: 2,
- /// inset: (
- /// x: 20pt,
- /// y: 10pt,
- /// ),
- /// fill: (col, _) => (red, blue).at(col),
- /// [Hello],
- /// [World],
- /// )
- /// ```
+ /// You can find an example for this argument at the
+ /// [`table.inset`]($table.inset) parameter.
#[fold]
pub inset: Celled<Sides<Option<Rel<Length>>>>,
@@ -508,6 +537,10 @@ impl TryFrom<Content> for GridItem {
}
/// A repeatable grid header.
+///
+/// If `repeat` is set to `true`, the header will be repeated across pages. For
+/// an example, refer to the [`table.header`]($table.header) element and the
+/// [`grid.stroke`]($grid.stroke) parameter.
#[elem(name = "header", title = "Grid Header")]
pub struct GridHeader {
/// Whether this header should be repeated across pages.
@@ -520,6 +553,11 @@ pub struct GridHeader {
}
/// A repeatable grid footer.
+///
+/// Just like the [`grid.header`]($grid.header) element, the footer can repeat
+/// itself on every page of the table.
+///
+/// No other grid cells may be placed after the footer.
#[elem(name = "footer", title = "Grid Footer")]
pub struct GridFooter {
/// Whether this footer should be repeated across pages.
@@ -533,9 +571,12 @@ pub struct GridFooter {
/// A horizontal line in the grid.
///
-/// Overrides any per-cell stroke, including stroke specified through the
-/// grid's `stroke` field. Can cross spacing between cells created through
-/// the grid's `column-gutter` option.
+/// Overrides any per-cell stroke, including stroke specified through the grid's
+/// `stroke` field. Can cross spacing between cells created through the grid's
+/// `column-gutter` option.
+///
+/// An example for this function can be found at the
+/// [`table.hline`]($table.hline) element.
#[elem(name = "hline", title = "Grid Horizontal Line")]
pub struct GridHLine {
/// The row above which the horizontal line is placed (zero-indexed).
@@ -644,53 +685,46 @@ pub struct GridVLine {
pub position: OuterHAlignment,
}
-/// A cell in the grid. Use this to either override grid properties for a
-/// particular cell, or in show rules to apply certain styles to multiple cells
-/// at once.
+/// A cell in the grid. You can use this function in the argument list of a grid
+/// to override grid style properties for an individual cell or manually
+/// positioning it within the grid. You can also use this function in show rules
+/// to apply certain styles to multiple cells at once.
///
-/// For example, you can override the fill, alignment or inset for a single
-/// cell:
+/// For example, you can override the position and stroke for a single cell:
///
/// ```example
-/// #grid(
-/// columns: 2,
-/// fill: red,
-/// align: left,
-/// inset: 5pt,
-/// [ABC], [ABC],
-/// grid.cell(fill: blue)[C], [D],
-/// grid.cell(align: center)[E], [F],
-/// [G], grid.cell(inset: 0pt)[H]
-/// )
-/// ```
+/// >>> #set page(width: auto)
+/// >>> #set text(15pt, font: "Noto Sans Symbols 2", bottom-edge: -.2em)
+/// <<< #set text(15pt, font: "Noto Sans Symbols 2")
+/// #show regex("[♚-♟︎]"): set text(fill: rgb("21212A"))
+/// #show regex("[♔-♙]"): set text(fill: rgb("111015"))
///
-/// You may also apply a show rule on `grid.cell` to style all cells at once,
-/// which allows you, for example, to apply styles based on a cell's position:
+/// #grid(
+/// fill: (x, y) => rgb(
+/// if calc.odd(x + y) { "EFF0F3" }
+/// else { "7F8396" }
+/// ),
+/// columns: (1em,) * 8,
+/// rows: 1em,
+/// align: center + horizon,
///
-/// ```example
-/// #show grid.cell: it => {
-/// if it.y == 0 {
-/// // First row is bold
-/// strong(it)
-/// } else if it.x == 1 {
-/// // Second column is italicized
-/// // (except at the first row)
-/// emph(it)
-/// } else {
-/// // Remaining cells aren't changed
-/// it
-/// }
-/// }
+/// [♜], [♞], [♝], [♛], [♚], [♝], [♞], [♜],
+/// [♟], [♟], [♟], [♟], [], [♟], [♟], [♟],
+/// grid.cell(
+/// x: 4, y: 3,
+/// stroke: blue.transparentize(60%)
+/// )[♟],
///
-/// #grid(
-/// columns: 3,
-/// gutter: 3pt,
-/// [Name], [Age], [Info],
-/// [John], [52], [Nice],
-/// [Mary], [50], [Cool],
-/// [Jake], [49], [Epic]
+/// ..(grid.cell(y: 6)[♙],) * 8,
+/// ..([♖], [♘], [♗], [♕], [♔], [♗], [♘], [♖])
+/// .map(grid.cell.with(y: 7)),
/// )
/// ```
+///
+/// You may also apply a show rule on `grid.cell` to style all cells at once,
+/// which allows you, for example, to apply styles based on a cell's position.
+/// Refer to the examples of the [`table.cell`]($table.cell) element to learn
+/// more about this.
#[elem(name = "cell", title = "Grid Cell", Show)]
pub struct GridCell {
/// The cell's body.
@@ -710,14 +744,21 @@ pub struct GridCell {
/// position before cells with automatic positions).
///
/// ```example
+ /// #let circ(c) = circle(
+ /// fill: c, width: 5mm
+ /// )
+ ///
/// #grid(
/// columns: 4,
- /// rows: 2.5em,
- /// fill: (x, y) => if calc.odd(x + y) { blue.lighten(50%) } else { blue.lighten(10%) },
+ /// rows: 7mm,
+ /// stroke: .5pt + blue,
/// align: center + horizon,
- /// inset: 3pt,
- /// grid.cell(x: 2, y: 2)[3],
- /// [1], grid.cell(x: 3)[4], [2],
+ /// inset: 1mm,
+ ///
+ /// grid.cell(x: 2, y: 2, circ(aqua)),
+ /// circ(yellow),
+ /// grid.cell(x: 3, circ(green)),
+ /// circ(black),
/// )
/// ```
pub x: Smart<usize>,
@@ -732,11 +773,21 @@ pub struct GridCell {
/// columns in the chosen row are already occupied, an error is raised.
///
/// ```example
+ /// #let tri(c) = polygon.regular(
+ /// fill: c,
+ /// size: 5mm,
+ /// vertices: 3,
+ /// )
+ ///
/// #grid(
/// columns: 2,
- /// fill: (x, y) => if calc.odd(x + y) { gray.lighten(40%) },
- /// inset: 1pt,
- /// [A], grid.cell(y: 1)[B], grid.cell(y: 1)[C], grid.cell(y: 2)[D]
+ /// stroke: blue,
+ /// inset: 1mm,
+ ///
+ /// tri(black),
+ /// grid.cell(y: 1, tri(teal)),
+ /// grid.cell(y: 1, tri(red)),
+ /// grid.cell(y: 2, tri(orange))
/// )
/// ```
pub y: Smart<usize>,
@@ -749,16 +800,16 @@ pub struct GridCell {
#[default(NonZeroUsize::ONE)]
pub rowspan: NonZeroUsize,
- /// The cell's fill override.
+ /// The cell's [fill]($grid.fill) override.
pub fill: Smart<Option<Paint>>,
- /// The cell's alignment override.
+ /// The cell's [alignment]($grid.align) override.
pub align: Smart<Alignment>,
- /// The cell's inset override.
+ /// The cell's [inset]($grid.inset) override.
pub inset: Smart<Sides<Option<Rel<Length>>>>,
- /// The cell's stroke override.
+ /// The cell's [stroke]($grid.stroke) override.
#[resolve]
#[fold]
pub stroke: Sides<Option<Option<Arc<Stroke>>>>,
diff --git a/crates/typst/src/model/table.rs b/crates/typst/src/model/table.rs
index c3bf3dbc..daa05723 100644
--- a/crates/typst/src/model/table.rs
+++ b/crates/typst/src/model/table.rs
@@ -25,14 +25,26 @@ use crate::visualize::{Paint, Stroke};
/// Tables are used to arrange content in cells. Cells can contain arbitrary
/// content, including multiple paragraphs and are specified in row-major order.
/// Because tables are just grids with different defaults for some cell
-/// properties (notably `stroke` and `inset`), refer to the
-/// [grid documentation]($grid) for more information on how to size the table
-/// tracks and specify the cell appearance properties.
+/// properties (notably `stroke` and `inset`), refer to the [grid
+/// documentation]($grid) for more information on how to size the table tracks
+/// and specify the cell appearance properties.
///
-/// Note that, to override a particular cell's properties or apply show rules
-/// on table cells, you can use the [`table.cell`]($table.cell) element (but
-/// not `grid.cell`, which is exclusive to grids). See its documentation for
-/// more information.
+/// If you are unsure whether you should be using a table or a grid, consider
+/// whether the content you are arranging semantically belongs together as a set
+/// of related data points or similar or whether you are just want to enhance
+/// your presentation by arranging unrelated content in a grid. In the former
+/// case, a table is the right choice, while in the latter case, a grid is more
+/// appropriate. Furthermore, Typst will annotate its output in the future such
+/// that screenreaders will annouce content in `table` as tabular while a grid's
+/// content will be announced no different than multiple content blocks in the
+/// document flow.
+///
+/// Note that, to override a particular cell's properties or apply show rules on
+/// table cells, you can use the [`table.cell`]($table.cell) element. See its
+/// documentation for more information.
+///
+/// Although the `table` and the `grid` share most properties, set and show
+/// rules on one of them do not affect the other.
///
/// To give a table a caption and make it [referenceable]($ref), put it into a
/// [figure].
@@ -45,7 +57,9 @@ use crate::visualize::{Paint, Stroke};
/// columns: (1fr, auto, auto),
/// inset: 10pt,
/// align: horizon,
-/// [], [*Area*], [*Parameters*],
+/// table.header(
+/// [], [*Area*], [*Parameters*],
+/// ),
/// image("cylinder.svg"),
/// $ pi h (D^2 - d^2) / 4 $,
/// [
@@ -63,33 +77,44 @@ use crate::visualize::{Paint, Stroke};
/// the appearance and the position of each cell.
///
/// ```example
-/// #set page(width: auto)
+/// >>> #set page(width: auto)
+/// >>> #set text(font: "IBM Plex Sans")
+/// >>> #let gray = rgb("#565565")
+/// >>>
+/// #set table(
+/// stroke: none,
+/// gutter: 0.2em,
+/// fill: (x, y) =>
+/// if x == 0 or y == 0 { gray },
+/// inset: (right: 1.5em),
+/// )
+///
/// #show table.cell: it => {
/// if it.x == 0 or it.y == 0 {
/// set text(white)
/// strong(it)
/// } else if it.body == [] {
/// // Replace empty cells with 'N/A'
-/// pad(rest: it.inset)[_N/A_]
+/// pad(..it.inset)[_N/A_]
/// } else {
/// it
/// }
/// }
///
+/// #let a = table.cell(
+/// fill: green.lighten(60%),
+/// )[A]
+/// #let b = table.cell(
+/// fill: aqua.lighten(60%),
+/// )[B]
+///
/// #table(
-/// fill: (x, y) => if x == 0 or y == 0 { gray.darken(50%) },
/// columns: 4,
/// [], [Exam 1], [Exam 2], [Exam 3],
-/// ..([John], [Mary], [Jake], [Robert]).map(table.cell.with(x: 0)),
-///
-/// // Mary got grade A on Exam 3.
-/// table.cell(x: 3, y: 2, fill: green)[A],
///
-/// // Everyone got grade A on Exam 2.
-/// ..(table.cell(x: 2, fill: green)[A],) * 4,
-///
-/// // Robert got grade B on other exams.
-/// ..(table.cell(y: 4, fill: aqua)[B],) * 2,
+/// [John], [], a, [],
+/// [Mary], [], a, a,
+/// [Robert], b, a, b,
/// )
/// ```
#[elem(scope, LayoutMultiple, LocalName, Figurable)]
@@ -157,7 +182,7 @@ pub struct TableElem {
/// ```example
/// #table(
/// columns: 3,
- /// align: (x, y) => (left, center, right).at(x),
+ /// align: (left, center, right),
/// [Hello], [Hello], [Hello],
/// [A], [B], [C],
/// )
@@ -172,10 +197,11 @@ pub struct TableElem {
/// If it is necessary to place lines which can cross spacing between cells
/// produced by the `gutter` option, or to override the stroke between
/// multiple specific cells, consider specifying one or more of
- /// [`table.hline`]($table.hline) and [`table.vline`]($table.vline) alongside
- /// your table cells.
+ /// [`table.hline`]($table.hline) and [`table.vline`]($table.vline)
+ /// alongside your table cells.
///
- /// See the [grid documentation]($grid) for more information on stroke.
+ /// See the [grid documentation]($grid.stroke) for more information on
+ /// strokes.
#[resolve]
#[fold]
#[default(Celled::Value(Sides::splat(Some(Some(Arc::new(Stroke::default()))))))]
@@ -464,6 +490,49 @@ impl TryFrom<Content> for TableItem {
}
/// A repeatable table header.
+///
+/// You should wrap your tables' heading rows in this function even if you do not
+/// plan to wrap your table across pages because Typst will use this function to
+/// attach accessibility metadata to tables in the future and ensure universal
+/// access to your document.
+///
+/// You can use the `repeat` parameter to control whether your table's header
+/// will be repeated across pages.
+///
+/// ```example
+/// #set page(height: 11.5em)
+/// #set table(
+/// fill: (x, y) =>
+/// if x == 0 or y == 0 {
+/// gray.lighten(40%)
+/// },
+/// align: right,
+/// )
+///
+/// #show table.cell.where(x: 0): strong
+/// #show table.cell.where(y: 0): strong
+///
+/// #table(
+/// columns: 4,
+/// table.header(
+/// [], [Blue chip],
+/// [Fresh IPO], [Penny st'k],
+/// ),
+/// table.cell(
+/// rowspan: 6,
+/// align: horizon,
+/// rotate(-90deg, reflow: true)[
+/// *USD / day*
+/// ],
+/// ),
+/// [0.20], [104], [5],
+/// [3.17], [108], [4],
+/// [1.59], [84], [1],
+/// [0.26], [98], [15],
+/// [0.01], [195], [4],
+/// [7.34], [57], [2],
+/// )
+/// ```
#[elem(name = "header", title = "Table Header")]
pub struct TableHeader {
/// Whether this header should be repeated across pages.
@@ -476,6 +545,13 @@ pub struct TableHeader {
}
/// A repeatable table footer.
+///
+/// Just like the [`table.header`]($table.header) element, the footer can repeat
+/// itself on every page of the table. This is useful for improving legibility
+/// by adding the column labels in both the header and footer of a large table,
+/// totals, or other information that should be visible on every page.
+///
+/// No other table cells may be placed after the footer.
#[elem(name = "footer", title = "Table Footer")]
pub struct TableFooter {
/// Whether this footer should be repeated across pages.
@@ -487,17 +563,42 @@ pub struct TableFooter {
pub children: Vec<TableItem>,
}
-/// A horizontal line in the table. See the docs for
-/// [`grid.hline`]($grid.hline) for more information regarding how to use this
-/// element's fields.
+/// A horizontal line in the table.
///
/// Overrides any per-cell stroke, including stroke specified through the
-/// table's `stroke` field. Can cross spacing between cells created through
-/// the table's `column-gutter` option.
+/// table's `stroke` field. Can cross spacing between cells created through the
+/// table's [`column-gutter`]($table.column-gutter) option.
+///
+/// Use this function instead of the table's `stroke` field if you want to
+/// manually place a horizontal line at a specific position in a single table.
+/// Consider using [table's `stroke`]($table.stroke) field or [`table.cell`'s
+/// `stroke`]($table.cell.stroke) field instead if the line you want to place is
+/// part of all your tables' designs.
+///
+/// ```example
+/// #set table.hline(stroke: .6pt)
+///
+/// #table(
+/// stroke: none,
+/// columns: (auto, 1fr),
+/// [09:00], [Badge pick up],
+/// [09:45], [Opening Keynote],
+/// [10:30], [Talk: Typst's Future],
+/// [11:15], [Session: Good PRs],
+/// table.hline(start: 1),
+/// [Noon], [_Lunch break_],
+/// table.hline(start: 1),
+/// [14:00], [Talk: Tracked Layout],
+/// [15:00], [Talk: Automations],
+/// [16:00], [Workshop: Tables],
+/// table.hline(),
+/// [19:00], [Day 1 Attendee Mixer],
+/// )
+/// ```
#[elem(name = "hline", title = "Table Horizontal Line")]
pub struct TableHLine {
/// The row above which the horizontal line is placed (zero-indexed).
- /// Functions identically to the `y` field in [`grid.hline`]($grid.hline).
+ /// Functions identically to the `y` field in [`grid.hline`]($grid.hline.y).
pub y: Smart<usize>,
/// The column at which the horizontal line starts (zero-indexed, inclusive).
@@ -531,8 +632,14 @@ pub struct TableHLine {
/// for more information regarding how to use this element's fields.
///
/// Overrides any per-cell stroke, including stroke specified through the
-/// table's `stroke` field. Can cross spacing between cells created through
-/// the table's `row-gutter` option.
+/// table's `stroke` field. Can cross spacing between cells created through the
+/// table's [`row-gutter`]($table.row-gutter) option.
+///
+/// Similar to [`table.hline`]($table.hline), use this function if you want to
+/// manually place a vertical line at a specific position in a single table and
+/// use the [table's `stroke`]($table.stroke) field or [`table.cell`'s
+/// `stroke`]($table.cell.stroke) field instead if the line you want to place is
+/// part of all your tables' designs.
#[elem(name = "vline", title = "Table Vertical Line")]
pub struct TableVLine {
/// The column before which the horizontal line is placed (zero-indexed).
@@ -571,50 +678,85 @@ pub struct TableVLine {
pub position: OuterHAlignment,
}
-/// A cell in the table. Use this to either override table properties for a
-/// particular cell, or in show rules to apply certain styles to multiple cells
-/// at once.
+/// A cell in the table. Use this to position a cell manually or to apply
+/// styling. To do the latter, you can either use the function to override the
+/// properties for a particular cell, or use it in show rules to apply certain
+/// styles to multiple cells at once.
+///
+/// Perhaps the most important use-case of `{table.cell}` is to make a cell span
+/// multiple columns or rows with the `colspan` and `rowspan` fields.
+///
+/// ```example
+/// >>> #set page(width: auto)
+/// >>> #show table.cell.where(y: 0): strong
+/// >>> #set table(
+/// >>> stroke: (x, y) => if y == 0 {
+/// >>> (bottom: 0.7pt + black)
+/// >>> },
+/// >>> align: (x, y) =>
+/// >>> if x > 0 { center }
+/// >>> else { left }
+/// >>> )
+/// #table(
+/// columns: 3,
+/// table.header(
+/// [Substance],
+/// [Subcritical °C],
+/// [Supercritical °C],
+/// ),
+/// [Hydrochloric Acid],
+/// [12.0], [92.1],
+/// [Sodium Myreth Sulfate],
+/// [16.6], [104],
+/// [Potassium Hydroxide],
+/// table.cell(colspan: 2)[24.7],
+/// )
+/// ```
///
/// For example, you can override the fill, alignment or inset for a single
/// cell:
///
/// ```example
+/// >>> #set page(width: auto)
+/// // You can also import those.
+/// #import table: cell, header
+///
/// #table(
/// columns: 2,
-/// fill: green,
-/// align: right,
-/// [*Name*], [*Data*],
-/// table.cell(fill: blue)[J.], [Organizer],
-/// table.cell(align: center)[K.], [Leader],
-/// [M.], table.cell(inset: 0pt)[Player]
+/// align: center,
+/// header(
+/// [*Trip progress*],
+/// [*Itinerary*],
+/// ),
+/// cell(
+/// align: right,
+/// fill: fuchsia.lighten(80%),
+/// [🚗],
+/// ),
+/// [Get in, folks!],
+/// [🚗], [Eat curbside hotdog],
+/// cell(align: left)[🌴🚗],
+/// cell(
+/// inset: 0.06em,
+/// text(1.62em)[🛖🌅🌊],
+/// ),
/// )
/// ```
///
-/// You may also apply a show rule on `table.cell` to style all cells at once,
-/// which allows you, for example, to apply styles based on a cell's position:
+/// You may also apply a show rule on `table.cell` to style all cells at once.
+/// Combined with selectors, this allows you to apply styles based on a cell's
+/// position:
///
/// ```example
-/// #show table.cell: it => {
-/// if it.y == 0 {
-/// // First row is bold
-/// strong(it)
-/// } else if it.x == 1 {
-/// // Second column is italicized
-/// // (except at the first row)
-/// emph(it)
-/// } else {
-/// // Remaining cells aren't changed
-/// it
-/// }
-/// }
+/// #show table.cell.where(x: 0): strong
///
/// #table(
/// columns: 3,
/// gutter: 3pt,
-/// [Name], [Age], [Info],
-/// [John], [52], [Nice],
-/// [Mary], [50], [Cool],
-/// [Jake], [49], [Epic]
+/// [Name], [Age], [Strength],
+/// [Hannes], [36], [Grace],
+/// [Irma], [50], [Resourcefulness],
+/// [Vikram], [49], [Perseverance],
/// )
/// ```
#[elem(name = "cell", title = "Table Cell", Show)]
@@ -631,9 +773,6 @@ pub struct TableCell {
/// Functions identically to the `y` field in [`grid.cell`]($grid.cell).
pub y: Smart<usize>,
- /// The cell's fill override.
- pub fill: Smart<Option<Paint>>,
-
/// The amount of columns spanned by this cell.
#[default(NonZeroUsize::ONE)]
pub colspan: NonZeroUsize,
@@ -642,13 +781,16 @@ pub struct TableCell {
#[default(NonZeroUsize::ONE)]
rowspan: NonZeroUsize,
- /// The cell's alignment override.
+ /// The cell's [fill]($table.fill) override.
+ pub fill: Smart<Option<Paint>>,
+
+ /// The cell's [alignment]($table.align) override.
pub align: Smart<Alignment>,
- /// The cell's inset override.
+ /// The cell's [inset]($table.inset) override.
pub inset: Smart<Sides<Option<Rel<Length>>>>,
- /// The cell's stroke override.
+ /// The cell's [stroke]($table.stroke) override.
#[resolve]
#[fold]
pub stroke: Sides<Option<Option<Arc<Stroke>>>>,