Skip to content

Commit

Permalink
feat: Add ui.layout_columns() (#856)
Browse files Browse the repository at this point in the history
  • Loading branch information
gadenbuie committed Dec 12, 2023
1 parent 8f14c92 commit 75f54d1
Show file tree
Hide file tree
Showing 15 changed files with 448 additions and 25 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Closed #814: The functions `reactive.Calc` and `reactive.Effect` have been changed to have lowercase names: `reactive.calc`, and `reactive.effect`. The old capitalized names are now aliases to the new lowercase names, so existing code will continue to work. Similarly, the class `reactive.Value` has a new alias, `reactive.value`, but in this case, since the original was a class, it keeps the original capitalized name as the primary name. The examples have not been changed yet, but will be changed in a future release. (#822)

* Added `ui.layout_columns()` for creating responsive column-forward layouts based on Bootstrap's 12-column CSS Grid. (#856)

### Bug fixes

* Fix support for `shiny.ui.accordion(multiple=)` (#799).
Expand Down
2 changes: 1 addition & 1 deletion scripts/htmlDependencies.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ versions <- list()
message("Installing GitHub packages: bslib, shiny, htmltools")
withr::local_temp_libpaths()
ignore <- capture.output({
pak::pkg_install(c("cran::bslib", "cran::shiny", "cran::htmltools"))
pak::pkg_install(c("rstudio/bslib", "cran::shiny", "cran::htmltools"))
#pak::pkg_install(c("rstudio/bslib@main", "rstudio/shiny@main", "rstudio/htmltools@main"))
})

Expand Down
2 changes: 1 addition & 1 deletion shiny/_versions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
shiny_html_deps = "1.8.0"
bslib = "0.6.1"
bslib = "0.6.1.9000"
htmltools = "0.5.7"
bootstrap = "5.3.1"
requirejs = "2.3.6"
Expand Down
111 changes: 111 additions & 0 deletions shiny/express/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from .. import ui
from ..types import MISSING, MISSING_TYPE
from ..ui._layout_columns import BreakpointsUser
from ..ui.css import CssUnit
from . import _run
from ._recall_context import RecallContextManager, wrap_recall_context_manager
Expand All @@ -19,6 +20,7 @@
"pre",
"sidebar",
"layout_column_wrap",
"layout_columns",
"column",
"row",
"card",
Expand Down Expand Up @@ -206,6 +208,11 @@ def layout_column_wrap(
-------
:
A :class:`~htmltools.Tag` element.
See Also
--------
* :func:`~shiny.express.layout.layout_columns` for laying out elements into a
responsive 12-column grid.
"""
return RecallContextManager(
ui.layout_column_wrap,
Expand All @@ -225,6 +232,110 @@ def layout_column_wrap(
)


def layout_columns(
*,
col_widths: BreakpointsUser[int] = None,
row_heights: BreakpointsUser[CssUnit] = None,
fill: bool = True,
fillable: bool = True,
gap: Optional[CssUnit] = None,
class_: Optional[str] = None,
height: Optional[CssUnit] = None,
**kwargs: TagAttrValue,
):
"""
Create responsive, column-based grid layouts, based on a 12-column grid.
Parameters
----------
col_widths
The widths of the columns, possibly at different breakpoints. Can be one of the
following:
* `None` (the default): Automatically determines a sensible number of columns
based on the number of children given to the layout.
* A list or tuple of integers between 1 and 12, where each element represents
the number of columns for the relevant UI element. Column widths are recycled
to extend the values in `col_widths` to match the actual number of items in
the layout, and children are wrapped onto the next row when a row exceeds 12
column units. For example, `col_widths=(4, 8, 12)` allocates 4 columns to the
first element, 8 columns to the second element, and 12 columns to the third
element (which wraps to the next row). Negative values are also allowed, and
are treated as empty columns. For example, `col_widths=(-2, 8, -2)` would
allocate 8 columns to an element (with 2 empty columns on either side).
* A dictionary of column widths at different breakpoints. The keys should be
one of `"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"`, or `"xxl"`, and the values are
either of the above. For example, `col_widths={"sm": (3, 3, 6), "lg": (4)}`.
row_heights
The heights of the rows, possibly at different breakpoints. Can be one of the
following:
* A numeric vector, where each value represents the
[fractional unit](https://css-tricks.com/introduction-fr-css-unit/)
(`fr`) height of the relevant row. If there are more rows than values
provided, the pattern will be repeated. For example, `row_heights=(1, 2)`
allows even rows to take up twice as much space as odd rows.
* A list of numeric or CSS length units, where each value represents the height
of the relevant row. If more rows are needed than values provided, the pattern
will repeat. For example, `row_heights=["auto", 1]` allows the height of odd
rows to be driven my it's contents and even rows to be
[`1fr`](https://css-tricks.com/introduction-fr-css-unit/).
* A single string containing CSS length units. In this case, the value is
supplied directly to `grid-auto-rows`.
* A dictionary of row heights at different breakpoints, where each key is a
breakpoint name (one of `"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"`, or `"xxl"`)
and where the values may be any of the above options.
fill
Whether or not to allow the layout to grow/shrink to fit a fillable container
with an opinionated height (e.g., :func:`~shiny.ui.page_fillable`).
fillable
Whether or not each element is wrapped in a fillable container.
gap
Any valid CSS unit to use for the gap between columns.
class_
CSS class(es) to apply to the containing element.
height
Any valid CSS unit to use for the height.
**kwargs
Additional attributes to apply to the containing element.
Returns
-------
:
An :class:`~htmltools.Tag` element.
See Also
--------
* :func:`~shiny.express.layout.layout_column_wrap` for laying out elements into a
uniform grid.
Reference
--------
* [Bootstrap CSS Grid](https://getbootstrap.com/docs/5.3/layout/grid/)
* [Bootstrap Breakpoints](https://getbootstrap.com/docs/5.3/layout/breakpoints/)
"""
return RecallContextManager(
ui.layout_columns,
kwargs=dict(
col_widths=col_widths,
row_heights=row_heights,
fill=fill,
fillable=fillable,
gap=gap,
class_=class_,
height=height,
**kwargs,
),
)


def column(width: int, *, offset: int = 0, **kwargs: TagAttrValue):
"""
Responsive row-column based layout
Expand Down
2 changes: 2 additions & 0 deletions shiny/ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
)

from ._layout import layout_column_wrap
from ._layout_columns import layout_columns


# Expose the following modules for extended usage: ex: ui.fill.as_fill_item(x)
Expand Down Expand Up @@ -185,6 +186,7 @@
"panel_sidebar",
"panel_main",
# _layout
"layout_columns",
"layout_column_wrap",
# _card
"CardItem",
Expand Down
5 changes: 5 additions & 0 deletions shiny/ui/_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ def layout_column_wrap(
-------
:
A :class:`~htmltools.Tag` element.
See Also
--------
* :func:`~shiny.ui.layout_columns` for laying out elements into a responsive
12-column grid.
"""
attrs, children = consolidate_attrs(*args, class_=class_, **kwargs)

Expand Down
Loading

0 comments on commit 75f54d1

Please sign in to comment.