Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

teal.widgets - bs345 #84

Merged
merged 18 commits into from
Sep 27, 2022
2 changes: 2 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ License: Apache License 2.0 | file LICENSE
Depends:
R (>= 3.6)
Imports:
bslib,
checkmate,
ggplot2,
graphics,
htmltools,
lifecycle,
methods,
rtables (>= 0.5.1),
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# teal.widgets 0.1.1.9018

### Breaking changes
* Updated `panel_group` and `panel_item` functions to no longer be an optional shiny input.

### Enhancements
* Updated `standard_layout` function to contain class not id for each output block.
* Added the `dim` slot to the list returned by the `plot_with_settings` module.
Expand Down
63 changes: 0 additions & 63 deletions R/accordion.R

This file was deleted.

4 changes: 4 additions & 0 deletions R/optionalInput.R
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ optionalSelectInput <- function(inputId, # nolint
"live-search" = ifelse(length(choices) > 10, TRUE, FALSE)
)

# if called outside the fluidPage then will assume bs 3
bs_version <- get_bs_version()
if (isTRUE(bs_version != "3")) default_options[["style"]] <- "btn-outline-secondary"

options <- if (!identical(options, list())) {
c(options, default_options[setdiff(names(default_options), names(options))])
} else {
Expand Down
176 changes: 90 additions & 86 deletions R/panel_group.R
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
#' Panel group widget
#'
#' @description `r lifecycle::badge("stable")`
#' @param input_id optional, (`character`)\cr
#' name of the panel group element. If supplied, this will register a shiny input variable that
#' indicates which panel item is open (accessed with `input$input_id`) and will collapse all other
#' panel items when one is open.
#' @description `r lifecycle::badge("experimental")`
#' @param id optional, (`character`)\cr
#' @param ... (`shiny.tag`)\cr
#' panels created by [panel_group()]
#'
#' @return (`shiny.tag`)
#'
#' @export
panel_group <- function(..., input_id = NULL) {
checkmate::assert_string(input_id, null.ok = TRUE)
panel_group <- function(..., id = NULL) {
checkmate::assert_string(id, null.ok = TRUE)

# panel-group
# div

tags$div(
id = input_id,
class = "panel-group",
shinyjs::useShinyjs(),
# allow input to be accessed on initialization without !is.null
# if server code runs before input initialized with JS (not teal)
if (!is.null(input_id)) shinyjs::hidden(tags$input(id = input_id, type = "text", value = "None")),
if (!is.null(input_id)) {
tags$head(tags$script(accordion(input_id)))
},
...
id = id,
...,
.renderHook = function(res_tag) {
bs_version <- get_bs_version()
if (bs_version == "3") {
htmltools::tagAppendAttributes(res_tag, class = "panel-group")
} else if (bs_version %in% c("4", "5")) {
res_tag <- htmltools::tagAppendAttributes(res_tag, class = "my-4")
htmltools::tagQuery(res_tag)$
find(".card")$
removeClass("my-2")$
allTags()
} else {
stop("Bootstrap 3, 4, and 5 are supported.")
}
}
)
}

#' Panel widget
#' @md
#'
#' @description `r lifecycle::badge("stable")`
#' @description `r lifecycle::badge("experimental")`
#' @param title (`character`)\cr title of panel
#' @param ... content of panel
#' @param collapsed (`logical`, optional)\cr
Expand All @@ -51,77 +57,75 @@ panel_item <- function(title, ..., collapsed = TRUE, input_id = NULL) {
div_id <- paste0(input_id, "_div")
panel_id <- paste0(input_id, "_panel_body_", sample(1:10000, 1))

tagList(
tags$head(tags$script(if (!is.null(input_id)) panel_status(input_id, div_id, panel_id))),
include_css_files(pattern = "panel.css"),
shinyjs::useShinyjs(),
# allow input to be accessed on initialization without !is.null
# if server code runs before input initialized with JS (not teal)
if (!is.null(input_id)) shinyjs::hidden(tags$input(id = input_id, type = "checkbox", value = collapsed)),
tags$div(
class = "panel panel-default",
tags$div(
id = div_id,
class = paste("panel-heading", ifelse(collapsed, "collapsed", "")),
`data-toggle` = "collapse",
href = paste0("#", panel_id),
`aria-expanded` = ifelse(collapsed, "false", "true"),
icon("angle-down", class = "dropdown-icon"),
tags$label(
class = "panel-title inline",
title,

tags$div(.renderHook = function(res_tag) {
bs_version <- get_bs_version()

# alter tag structure
if (bs_version == "3") {
res_tag$children <- list(
tags$div(
class = "panel panel-default",
tags$div(
id = div_id,
class = paste("panel-heading", ifelse(collapsed, "collapsed", "")),
`data-toggle` = "collapse",
href = paste0("#", panel_id),
`aria-expanded` = ifelse(collapsed, "false", "true"),
icon("angle-down", class = "dropdown-icon"),
tags$label(
class = "panel-title inline",
title,
)
),
tags$div(
class = paste("panel-collapse collapse", ifelse(collapsed, "", "in")),
id = panel_id,
tags$div(
class = "panel-body",
...
)
)
)
),
tags$div(
class = paste("panel-collapse collapse", ifelse(collapsed, "", "in")),
id = panel_id,
)
} else if (bs_version %in% c("4", "5")) {
res_tag$children <- list(
tags$div(
class = "panel-body",
...
class = "card my-2",
tags$div(
class = "card-header",
tags$div(
class = ifelse(collapsed, "collapsed", ""),
# bs4
`data-toggle` = "collapse",
# bs5
`data-bs-toggle` = "collapse",
href = paste0("#", panel_id),
`aria-expanded` = ifelse(collapsed, "false", "true"),
icon("angle-down", class = "dropdown-icon"),
tags$label(
class = "card-title inline",
title,
)
)
),
tags$div(
id = panel_id,
class = paste("collapse", ifelse(collapsed, "", "show")),
tags$div(
class = "card-body",
...
)
)
)
)
)
)
}
} else {
stop("Bootstrap 3, 4, and 5 are supported.")
}


#' Get Collapsible Panel Status
#'
#' Javascript to get open or close status of a panel item.
#' @md
#'
#' @param input_id (`character`)\cr
#' string with which to register a shiny input. The title of the currently open panel (or last
#' opened panel) will be accessible with `input$input_id`.
#' @param div_id (`character`)\cr
#' string giving the id of the `div` to listen for collapse events on.
#' @param panel_id (`character`)\cr
#' string giving the id of the panel to determine the initial collapsed status.
#' @keywords internal
panel_status <- function(input_id, div_id, panel_id) {
paste0("
$(document).ready(function(event) { // wait for all HTML elements to be loaded
var panel_item = document.querySelector('#", div_id, "');

var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type == 'attributes') {
// is the element collapsed or not
var aria = document.getElementById('", div_id, "').getAttribute('aria-expanded');
var collapsed = (aria == 'false'); // convert to boolean
Shiny.onInputChange('", input_id, "', collapsed); // update shiny input
}
});
});

observer.observe(panel_item, {
attributes: true // listen for attribute changes
});

// set initial value
var aria = document.getElementById('", panel_id, "').classList.contains('in');
var collapsed = (aria == false);
Shiny.onInputChange('", input_id, "', collapsed);
});
")
tagList(
include_css_files(pattern = "panel.css"),
res_tag
)
})
}
2 changes: 1 addition & 1 deletion R/standard_layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ standard_layout <- function(output,
)

tag_enc_out <- if (!is.null(encoding)) {
div(
tagList(
div(
class = "col-md-3",
div(class = "well", encoding),
Expand Down
11 changes: 11 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#' Get bootstrap current version
#' @note will work properly mainly inside a tag `.renderHook`
#' @keywords internal
get_bs_version <- function() {
theme <- bslib::bs_current_theme()
if (bslib::is_bs_theme(theme)) {
bslib::theme_version(theme)
} else {
"3"
}
}
16 changes: 8 additions & 8 deletions inst/css/panel.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* teal.widgets panel css */

.panel-title {
font-size: 14px;
} /* same as everywhere else */

.panel-body {
background-color: #f5f5f5;
} /* same as panel-title */

.inline {
display: inline;
}

.my-4 {
margin: 1rem 0;
}

.my-2 {
margin: 0.5rem 0;
}
6 changes: 6 additions & 0 deletions inst/css/picker_input.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/* teal.widgets picker_input css */

/* to set the alignment of pickerInput dropdowns */
/* boostrap 3 */
.dropdown-menu.open {
width: 100%;
}
/* boostrap 4 and 5 */
.dropdown-menu.show {
width: 100%;
overflow: auto;
}
18 changes: 0 additions & 18 deletions man/accordion.Rd

This file was deleted.

15 changes: 15 additions & 0 deletions man/get_bs_version.Rd

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

Loading