Skip to content

Commit

Permalink
New nav() api providing legacy support for shiny's tabPanel() logic (#…
Browse files Browse the repository at this point in the history
…314)

* New nav() api providing legacy support for shiny's tabPanel() logic

* wip doc improvements

* Resave data (GitHub Action)

* Document (GitHub Actions)

* Various cleanup

* More wip docs

* Document (GitHub Actions)

* Simplify static rendering logic (rstudio/shiny#3402 should fix issues with handling bootstrapLib() state during static render)

* Document (GitHub Actions)

* Make it more clear that functions reside in bslib

* More doc improvements

* Document (GitHub Actions)

* Don't re-export appendTab()/prependTab() (we should consider them deprecated at this point)

* Default target to NULL in insertTab()

* Finish up

* Document (GitHub Actions)

* Fix Rd link

* Update pkgdown reference

Co-authored-by: cpsievert <[email protected]>
  • Loading branch information
cpsievert and cpsievert authored May 25, 2021
1 parent 9e60ac1 commit 112ae6e
Show file tree
Hide file tree
Showing 28 changed files with 1,272 additions and 3 deletions.
10 changes: 8 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: bslib
Title: Custom 'Bootstrap' 'Sass' Themes for 'shiny' and 'rmarkdown'
Version: 0.2.5.9000
Version: 0.2.5.9001
Authors@R: c(
person("Carson", "Sievert", role = c("aut", "cre"), email = "[email protected]", comment = c(ORCID = "0000-0002-4958-2844")),
person("Joe", "Cheng", role = "aut", email = "[email protected]"),
Expand All @@ -20,7 +20,7 @@ Description: Simplifies custom 'CSS' styling of both 'shiny' and 'rmarkdown' via
Depends: R (>= 2.10)
Imports:
grDevices,
htmltools (>= 0.5.1),
htmltools (>= 0.5.1.9004),
jsonlite,
sass (>= 0.4.0),
jquerylib (>= 0.1.3),
Expand Down Expand Up @@ -54,10 +54,16 @@ Collate:
'deprecated.R'
'files.R'
'imports.R'
'nav-update.R'
'navs-legacy.R'
'onLoad.R'
'page.R'
'precompiled.R'
'print.R'
'shiny-devmode.R'
'utils-shiny.R'
'version-default.R'
'versions.R'
URL: https://rstudio.github.io/bslib/, https://github.com/rstudio/bslib
BugReports: https://github.com/rstudio/bslib/issues
Remotes: rstudio/htmltools
20 changes: 20 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Generated by roxygen2: do not edit by hand

S3method(print,bslib_fragment)
S3method(print,bslib_page)
export("%>%")
export(bootstrap)
export(bootstrap_sass)
Expand All @@ -23,6 +25,7 @@ export(bs_global_get)
export(bs_global_set)
export(bs_global_theme)
export(bs_global_theme_update)
export(bs_page)
export(bs_remove)
export(bs_retrieve)
export(bs_theme)
Expand All @@ -45,6 +48,21 @@ export(font_face)
export(font_google)
export(font_link)
export(is_bs_theme)
export(nav)
export(nav_content)
export(nav_hide)
export(nav_insert)
export(nav_menu)
export(nav_remove)
export(nav_select)
export(nav_show)
export(navs_bar)
export(navs_hidden)
export(navs_pill)
export(navs_pill_list)
export(navs_tab)
export(page_fixed)
export(page_fluid)
export(precompiled_css_path)
export(run_with_themer)
export(theme_bootswatch)
Expand All @@ -53,11 +71,13 @@ export(version_default)
export(versions)
import(htmltools)
import(sass)
importFrom(grDevices,col2rgb)
importFrom(jquerylib,jquery_core)
importFrom(jsonlite,fromJSON)
importFrom(magrittr,"%>%")
importFrom(rlang,":=")
importFrom(rlang,is_missing)
importFrom(rlang,list2)
importFrom(rlang,maybe_missing)
importFrom(rlang,missing_arg)
importFrom(sass,font_collection)
Expand Down
3 changes: 2 additions & 1 deletion R/imports.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ utils::globalVariables("!!")
#' @import sass
#' @importFrom utils modifyList packageVersion download.file URLencode getFromNamespace
#' @importFrom stats setNames na.omit
#' @importFrom grDevices col2rgb
#' @importFrom tools file_path_sans_ext
#' @importFrom jquerylib jquery_core
#' @importFrom jsonlite fromJSON
#' @importFrom rlang :=
#' @importFrom rlang := list2
NULL

#' Pipe operator
Expand Down
129 changes: 129 additions & 0 deletions R/nav-update.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#' Dynamically update nav containers
#'
#' Functions for dynamically updating nav containers (e.g., select, insert, and
#' remove nav items). These functions require an `id` on the nav container to be
#' specified.
#'
#' @param id a character string used to identify the nav container.
#' @param selected a character string used to identify a particular [nav()] item.
#' @param session a shiny session object (the default should almost always be used).
#' @export
#' @seealso [nav()], [navs_tab()].
#' @examples
#'
#' can_browse <- function() interactive() && require("shiny")
#'
#' # Selecting a tab
#' if (can_browse()) {
#' shinyApp(
#' page_fluid(
#' radioButtons("item", "Choose", c("A", "B")),
#' navs_hidden(
#' id = "container",
#' nav_content("A", "a"),
#' nav_content("B", "b")
#' )
#' ),
#' function(input, output) {
#' observe(nav_select("container", input$item))
#' }
#' )
#' }
#'
#' # Inserting and removing
#' if (can_browse()) {
#' ui <- page_fluid(
#' actionButton("add", "Add 'Dynamic' tab"),
#' actionButton("remove", "Remove 'Foo' tab"),
#' navs_tab(
#' id = "tabs",
#' nav("Hello", "hello"),
#' nav("Foo", "foo"),
#' nav("Bar", "bar tab")
#' )
#' )
#' server <- function(input, output) {
#' observeEvent(input$add, {
#' nav_insert(
#' "tabs", target = "Bar", select = TRUE,
#' nav("Dynamic", "Dynamically added content")
#' )
#' })
#' observeEvent(input$remove, {
#' nav_remove("tabs", target = "Foo")
#' })
#' }
#' shinyApp(ui, server)
#' }
#'
nav_select <- function(id, selected = NULL,
session = getDefaultReactiveDomain()) {
shiny::updateTabsetPanel(session, id, selected)
}


#' @param nav a [nav()] item.
#' @param target The `value` of an existing `nav()` item, next to which tab will be added. If removing: the `value` of the `nav()` item that you want to remove.
#' @param position Should `nav` be added before or after the target?
#' @param select Should `nav` be selected upon being inserted?
#' @rdname nav_select
#' @export
nav_insert <- function(id, nav, target = NULL, position = c("after", "before"),
select = FALSE, session = getDefaultReactiveDomain()) {

force(target)
force(select)
position <- match.arg(position)
inputId <- session$ns(id)

# Barbara -- August 2017
# Note: until now, the number of tabs in a tabsetPanel (or navbarPage
# or navlistPanel) was always fixed. So, an easy way to give an id to
# a tab was simply incrementing a counter. (Just like it was easy to
# give a random 4-digit number to identify the tabsetPanel). Since we
# can only know this in the client side, we'll just pass `id` and
# `tsid` (TabSetID) as dummy values that will be fixed in the JS code.
item <- buildTabItem("id", "tsid", TRUE, divTag = nav,
textFilter = if (is.character(nav)) navbarMenuTextFilter else NULL)

callback <- function() {
session$sendInsertTab(
inputId = inputId,
liTag = processDeps(item$liTag, session),
divTag = processDeps(item$divTag, session),
menuName = NULL,
target = target,
position = position,
select = select)
}
session$onFlush(callback, once = TRUE)
}

#' @export
#' @rdname nav_select
nav_remove <- function(id, target, session = getDefaultReactiveDomain()) {
force(target)
inputId <- session$ns(id)

callback <- function() {
session$sendRemoveTab(
inputId = inputId,
target = target
)
}
session$onFlush(callback, once = TRUE)
}

#' @export
#' @rdname nav_select
nav_show <- function(id, target, select = FALSE,
session = getDefaultReactiveDomain()) {
shiny::showTab(id, target, select, session)
}

#' @export
#' @rdname nav_select
nav_hide <- function(id, target,
session = getDefaultReactiveDomain()) {
shiny::hideTab(id, target, session)
}
Loading

0 comments on commit 112ae6e

Please sign in to comment.