Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* `page_navbar()` now defaults to `underline = TRUE`, meaning that navigation links in the navbar now have underline styling by default (set `underline = FALSE` to revert to previous behavior). (#784)
* `page()` now returns a `<body>` tag instead of `tagList()`. This change allows `page()` to treat named arguments as HTML attributes. (#809)
* The JS/CSS assets behind `{bslib}` components (e.g., `card()`, `value_box()`, etc) are all now bundled into one `htmlDependency()` and included with the return value of `bs_theme_dependencies()` (previously they were attached at the component-level). (#810)
* `layout_column_wrap()` no longer requires `width` and `width` is no longer the first argument, meaning that `width` must be named if used. The new default is `width = "200px"`, which combines with `fixed_width = FALSE` and produces an automatically responsive layout where each column is at least 200px wide. This means that, in most cases, `layout_column_wrap()` can layout an unknown number of items without you having to set `width`. (#853)

## New features

Expand Down
51 changes: 42 additions & 9 deletions R/layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
#'
#' Wraps a 1d sequence of UI elements into a 2d grid. The number of columns (and
#' rows) in the grid dependent on the column `width` as well as the size of the
#' display. For more explanation and illustrative examples, see [here](https://rstudio.github.io/bslib/articles/cards.html#multiple-cards)
#' display. For more explanation and illustrative examples, see
#' [here](https://rstudio.github.io/bslib/articles/cards.html#multiple-cards).
#'
#' @param ... Unnamed arguments should be UI elements (e.g., [card()])
#' Named arguments become attributes on the containing [htmltools::tag] element.
#' @param ... Unnamed arguments should be UI elements (e.g., [card()]). Named
#' arguments become attributes on the containing [htmltools::tag] element.
#' @param width The desired width of each card, which can be any of the
#' following:
#' * A (unit-less) number between 0 and 1.
Expand Down Expand Up @@ -39,18 +40,23 @@
#' @inheritParams card
#' @inheritParams card_body
#'
#' @export
#' @examples
#'
#' x <- card("A simple card")
#' # Always has 2 columns (on non-mobile)
#' layout_column_wrap(1/2, x, x, x)
#' # Has three columns when viewport is wider than 750px
#' layout_column_wrap("250px", x, x, x)
#' layout_column_wrap(width = 1/2, x, x, x)
#'
#' # Automatically lays out three cards into columns
#' # such that each column is at least 200px wide:
#' layout_column_wrap(x, x, x)
#'
#' # To use larger column widths by default, set `width`.
#' # This example has 3 columns when the screen is at least 900px wide:
#' layout_column_wrap(width = "300px", x, x, x)
#'
#' @export
layout_column_wrap <- function(
width,
...,
width = "200px",
fixed_width = FALSE,
heights_equal = c("all", "row"),
fill = TRUE,
Expand All @@ -67,6 +73,23 @@ layout_column_wrap <- function(
attribs <- args$attribs
children <- args$children

if (missing(width)) {
first_is_width <-
is.null(children[[1]]) ||
is_probably_a_css_unit(children[[1]])

if (first_is_width) {
# Assume an unnamed first argument that matches our expectations for
# `width` is actually the width argument, with a warning
lifecycle::deprecate_warn(
"0.6.0",
"layout_column_wrap(width = 'must be named')"
)
width <- children[[1]]
children <- children[-1]
}
}

if (length(width) > 1) {
stop("`width` of length greater than 1 is not currently supported.")
}
Expand Down Expand Up @@ -118,6 +141,16 @@ layout_column_wrap <- function(
)
}

is_probably_a_css_unit <- function(x) {
if (length(x) != 1) return(FALSE)
if (is.numeric(x)) return(TRUE)
if (!is.character(x)) return(FALSE)
tryCatch(
{ validateCssUnit(x); TRUE },
error = function(e) FALSE
)
}

#' Responsive 12-column grid layouts
#'
#' Create responsive, column-based grid layouts, based on a 12-column grid.
Expand Down
24 changes: 15 additions & 9 deletions man/layout_column_wrap.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/layout_columns.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions tests/testthat/test-layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,51 @@ test_that("row_heights_css_vars() decides fr/px for numeric, passes character",
"--bslib-grid--row-heights--md:10px 1fr;"
)
})

test_that("layout_column_wrap() handles deprecated width as first arg", {
# first arg is fractional
lifecycle::expect_deprecated(
lc_implicit_width_frac <- layout_column_wrap(1/2, "one", "two")
)

expect_equal(
as.character(lc_implicit_width_frac),
as.character(layout_column_wrap(width = 1/2, "one", "two"))
)

# first arg is explicitly px character
lifecycle::expect_deprecated(
lc_implicit_width_px <- layout_column_wrap("400px", "one", "two")
)

expect_equal(
as.character(lc_implicit_width_px),
as.character(layout_column_wrap(width = "400px", "one", "two"))
)

# first arg is px, but numeric
lifecycle::expect_deprecated(
lc_implicit_width_px_implied <- layout_column_wrap(365, "one", "two")
)

expect_equal(
as.character(lc_implicit_width_px_implied),
as.character(layout_column_wrap(width = 365, "one", "two"))
)

# first arg is NULL
lifecycle::expect_deprecated(
lc_implicit_width_null <- layout_column_wrap(NULL, "one", "two")
)

expect_equal(
as.character(lc_implicit_width_null),
as.character(layout_column_wrap(width = NULL, "one", "two"))
)

# first arg is not a CSS unit
rlang::local_options(lifecycle_verbosity = "warning")
testthat::expect_silent(
as.character(layout_column_wrap("1ft", "one", "two"))
)
})