Spruce up table docs (#3593)

This commit is contained in:
Martin Haug 2024-03-09 17:42:11 +01:00 committed by GitHub
parent 639a8d0dc0
commit 15ac6c3166
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 412 additions and 219 deletions

View File

@ -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.
/// # Styling the grid
/// The grid's appearance can be customized through different parameters. These
/// are the most important ones:
///
/// ```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.
/// - [`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
///
/// // 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
/// }
/// }
/// 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.
///
/// #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"),
/// 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.
///
/// [Sun], [Mon], [Tue], [Wed], [Thu], [Fri], [Sat],
/// 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 on the first Friday (sixth column).
/// grid.cell(x: 5, fill: yellow.darken(10%))[Call],
/// ## 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.
///
/// // 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,
///
/// // This event will occur at day 19.
/// grid.cell(x: 4, y: 3, fill: orange.lighten(25%))[Talk],
///
/// // 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
/// >>> #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"))
///
/// #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]
/// fill: (x, y) => rgb(
/// if calc.odd(x + y) { "EFF0F3" }
/// else { "7F8396" }
/// ),
/// columns: (1em,) * 8,
/// rows: 1em,
/// align: center + horizon,
///
/// [♜], [♞], [♝], [♛], [♚], [♝], [♞], [♜],
/// [♟], [♟], [♟], [♟], [], [♟], [♟], [♟],
/// grid.cell(
/// x: 4, y: 3,
/// stroke: blue.transparentize(60%)
/// )[♟],
///
/// ..(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:
///
/// ```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(
/// columns: 3,
/// gutter: 3pt,
/// [Name], [Age], [Info],
/// [John], [52], [Nice],
/// [Mary], [50], [Cool],
/// [Jake], [49], [Epic]
/// )
/// ```
/// 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>>>>,

View File

@ -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>>>>,