Skip to content

Commit 112ae6e

Browse files
authored
New nav() api providing legacy support for shiny's tabPanel() logic (#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]>
1 parent 9e60ac1 commit 112ae6e

28 files changed

+1272
-3
lines changed

DESCRIPTION

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: bslib
22
Title: Custom 'Bootstrap' 'Sass' Themes for 'shiny' and 'rmarkdown'
3-
Version: 0.2.5.9000
3+
Version: 0.2.5.9001
44
Authors@R: c(
55
person("Carson", "Sievert", role = c("aut", "cre"), email = "[email protected]", comment = c(ORCID = "0000-0002-4958-2844")),
66
person("Joe", "Cheng", role = "aut", email = "[email protected]"),
@@ -20,7 +20,7 @@ Description: Simplifies custom 'CSS' styling of both 'shiny' and 'rmarkdown' via
2020
Depends: R (>= 2.10)
2121
Imports:
2222
grDevices,
23-
htmltools (>= 0.5.1),
23+
htmltools (>= 0.5.1.9004),
2424
jsonlite,
2525
sass (>= 0.4.0),
2626
jquerylib (>= 0.1.3),
@@ -54,10 +54,16 @@ Collate:
5454
'deprecated.R'
5555
'files.R'
5656
'imports.R'
57+
'nav-update.R'
58+
'navs-legacy.R'
5759
'onLoad.R'
60+
'page.R'
5861
'precompiled.R'
62+
'print.R'
5963
'shiny-devmode.R'
64+
'utils-shiny.R'
6065
'version-default.R'
6166
'versions.R'
6267
URL: https://rstudio.github.io/bslib/, https://github.com/rstudio/bslib
6368
BugReports: https://github.com/rstudio/bslib/issues
69+
Remotes: rstudio/htmltools

NAMESPACE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
S3method(print,bslib_fragment)
4+
S3method(print,bslib_page)
35
export("%>%")
46
export(bootstrap)
57
export(bootstrap_sass)
@@ -23,6 +25,7 @@ export(bs_global_get)
2325
export(bs_global_set)
2426
export(bs_global_theme)
2527
export(bs_global_theme_update)
28+
export(bs_page)
2629
export(bs_remove)
2730
export(bs_retrieve)
2831
export(bs_theme)
@@ -45,6 +48,21 @@ export(font_face)
4548
export(font_google)
4649
export(font_link)
4750
export(is_bs_theme)
51+
export(nav)
52+
export(nav_content)
53+
export(nav_hide)
54+
export(nav_insert)
55+
export(nav_menu)
56+
export(nav_remove)
57+
export(nav_select)
58+
export(nav_show)
59+
export(navs_bar)
60+
export(navs_hidden)
61+
export(navs_pill)
62+
export(navs_pill_list)
63+
export(navs_tab)
64+
export(page_fixed)
65+
export(page_fluid)
4866
export(precompiled_css_path)
4967
export(run_with_themer)
5068
export(theme_bootswatch)
@@ -53,11 +71,13 @@ export(version_default)
5371
export(versions)
5472
import(htmltools)
5573
import(sass)
74+
importFrom(grDevices,col2rgb)
5675
importFrom(jquerylib,jquery_core)
5776
importFrom(jsonlite,fromJSON)
5877
importFrom(magrittr,"%>%")
5978
importFrom(rlang,":=")
6079
importFrom(rlang,is_missing)
80+
importFrom(rlang,list2)
6181
importFrom(rlang,maybe_missing)
6282
importFrom(rlang,missing_arg)
6383
importFrom(sass,font_collection)

R/imports.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ utils::globalVariables("!!")
44
#' @import sass
55
#' @importFrom utils modifyList packageVersion download.file URLencode getFromNamespace
66
#' @importFrom stats setNames na.omit
7+
#' @importFrom grDevices col2rgb
78
#' @importFrom tools file_path_sans_ext
89
#' @importFrom jquerylib jquery_core
910
#' @importFrom jsonlite fromJSON
10-
#' @importFrom rlang :=
11+
#' @importFrom rlang := list2
1112
NULL
1213

1314
#' Pipe operator

R/nav-update.R

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#' Dynamically update nav containers
2+
#'
3+
#' Functions for dynamically updating nav containers (e.g., select, insert, and
4+
#' remove nav items). These functions require an `id` on the nav container to be
5+
#' specified.
6+
#'
7+
#' @param id a character string used to identify the nav container.
8+
#' @param selected a character string used to identify a particular [nav()] item.
9+
#' @param session a shiny session object (the default should almost always be used).
10+
#' @export
11+
#' @seealso [nav()], [navs_tab()].
12+
#' @examples
13+
#'
14+
#' can_browse <- function() interactive() && require("shiny")
15+
#'
16+
#' # Selecting a tab
17+
#' if (can_browse()) {
18+
#' shinyApp(
19+
#' page_fluid(
20+
#' radioButtons("item", "Choose", c("A", "B")),
21+
#' navs_hidden(
22+
#' id = "container",
23+
#' nav_content("A", "a"),
24+
#' nav_content("B", "b")
25+
#' )
26+
#' ),
27+
#' function(input, output) {
28+
#' observe(nav_select("container", input$item))
29+
#' }
30+
#' )
31+
#' }
32+
#'
33+
#' # Inserting and removing
34+
#' if (can_browse()) {
35+
#' ui <- page_fluid(
36+
#' actionButton("add", "Add 'Dynamic' tab"),
37+
#' actionButton("remove", "Remove 'Foo' tab"),
38+
#' navs_tab(
39+
#' id = "tabs",
40+
#' nav("Hello", "hello"),
41+
#' nav("Foo", "foo"),
42+
#' nav("Bar", "bar tab")
43+
#' )
44+
#' )
45+
#' server <- function(input, output) {
46+
#' observeEvent(input$add, {
47+
#' nav_insert(
48+
#' "tabs", target = "Bar", select = TRUE,
49+
#' nav("Dynamic", "Dynamically added content")
50+
#' )
51+
#' })
52+
#' observeEvent(input$remove, {
53+
#' nav_remove("tabs", target = "Foo")
54+
#' })
55+
#' }
56+
#' shinyApp(ui, server)
57+
#' }
58+
#'
59+
nav_select <- function(id, selected = NULL,
60+
session = getDefaultReactiveDomain()) {
61+
shiny::updateTabsetPanel(session, id, selected)
62+
}
63+
64+
65+
#' @param nav a [nav()] item.
66+
#' @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.
67+
#' @param position Should `nav` be added before or after the target?
68+
#' @param select Should `nav` be selected upon being inserted?
69+
#' @rdname nav_select
70+
#' @export
71+
nav_insert <- function(id, nav, target = NULL, position = c("after", "before"),
72+
select = FALSE, session = getDefaultReactiveDomain()) {
73+
74+
force(target)
75+
force(select)
76+
position <- match.arg(position)
77+
inputId <- session$ns(id)
78+
79+
# Barbara -- August 2017
80+
# Note: until now, the number of tabs in a tabsetPanel (or navbarPage
81+
# or navlistPanel) was always fixed. So, an easy way to give an id to
82+
# a tab was simply incrementing a counter. (Just like it was easy to
83+
# give a random 4-digit number to identify the tabsetPanel). Since we
84+
# can only know this in the client side, we'll just pass `id` and
85+
# `tsid` (TabSetID) as dummy values that will be fixed in the JS code.
86+
item <- buildTabItem("id", "tsid", TRUE, divTag = nav,
87+
textFilter = if (is.character(nav)) navbarMenuTextFilter else NULL)
88+
89+
callback <- function() {
90+
session$sendInsertTab(
91+
inputId = inputId,
92+
liTag = processDeps(item$liTag, session),
93+
divTag = processDeps(item$divTag, session),
94+
menuName = NULL,
95+
target = target,
96+
position = position,
97+
select = select)
98+
}
99+
session$onFlush(callback, once = TRUE)
100+
}
101+
102+
#' @export
103+
#' @rdname nav_select
104+
nav_remove <- function(id, target, session = getDefaultReactiveDomain()) {
105+
force(target)
106+
inputId <- session$ns(id)
107+
108+
callback <- function() {
109+
session$sendRemoveTab(
110+
inputId = inputId,
111+
target = target
112+
)
113+
}
114+
session$onFlush(callback, once = TRUE)
115+
}
116+
117+
#' @export
118+
#' @rdname nav_select
119+
nav_show <- function(id, target, select = FALSE,
120+
session = getDefaultReactiveDomain()) {
121+
shiny::showTab(id, target, select, session)
122+
}
123+
124+
#' @export
125+
#' @rdname nav_select
126+
nav_hide <- function(id, target,
127+
session = getDefaultReactiveDomain()) {
128+
shiny::hideTab(id, target, session)
129+
}

0 commit comments

Comments
 (0)