mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-11 16:08:19 -05:00
Compare commits
28 Commits
bindAfterR
...
file-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06024839f9 | ||
|
|
76022492ad | ||
|
|
0e47ff6e34 | ||
|
|
73c49f3c8c | ||
|
|
b054e45402 | ||
|
|
8b1d30aefe | ||
|
|
ab87a0708d | ||
|
|
0b97ee1ecc | ||
|
|
68546c319e | ||
|
|
69188fef22 | ||
|
|
6be6dfbfeb | ||
|
|
6fc06281bd | ||
|
|
f724128d41 | ||
|
|
518ef0f9f8 | ||
|
|
f5b395485e | ||
|
|
31aca7aa70 | ||
|
|
b38a630224 | ||
|
|
1b7709411b | ||
|
|
2b48aa0d91 | ||
|
|
6fdf23752e | ||
|
|
8542f5d017 | ||
|
|
e7b830755a | ||
|
|
23c7b0683a | ||
|
|
5805895581 | ||
|
|
90539bff25 | ||
|
|
62bb21d5b6 | ||
|
|
4f85268d44 | ||
|
|
611e517bb8 |
23
DESCRIPTION
23
DESCRIPTION
@@ -1,19 +1,19 @@
|
||||
Package: shiny
|
||||
Type: Package
|
||||
Title: Web Application Framework for R
|
||||
Version: 1.7.4.9002
|
||||
Version: 1.7.5.9000
|
||||
Authors@R: c(
|
||||
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com", comment = c(ORCID = "0000-0002-1576-2126")),
|
||||
person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"),
|
||||
person("JJ", "Allaire", role = "aut", email = "jj@rstudio.com"),
|
||||
person("Carson", "Sievert", role = "aut", email = "carson@rstudio.com", comment = c(ORCID = "0000-0002-4958-2844")),
|
||||
person("Barret", "Schloerke", role = "aut", email = "barret@rstudio.com", comment = c(ORCID = "0000-0001-9986-114X")),
|
||||
person("Yihui", "Xie", role = "aut", email = "yihui@rstudio.com"),
|
||||
person("Jeff", "Allen", role = "aut", email = "jeff@rstudio.com"),
|
||||
person("Jonathan", "McPherson", role = "aut", email = "jonathan@rstudio.com"),
|
||||
person("Winston", "Chang", role = c("aut", "cre"), email = "winston@posit.co", comment = c(ORCID = "0000-0002-1576-2126")),
|
||||
person("Joe", "Cheng", role = "aut", email = "joe@posit.co"),
|
||||
person("JJ", "Allaire", role = "aut", email = "jj@posit.co"),
|
||||
person("Carson", "Sievert", role = "aut", email = "carson@posit.co", comment = c(ORCID = "0000-0002-4958-2844")),
|
||||
person("Barret", "Schloerke", role = "aut", email = "barret@posit.co", comment = c(ORCID = "0000-0001-9986-114X")),
|
||||
person("Yihui", "Xie", role = "aut", email = "yihui@posit.co"),
|
||||
person("Jeff", "Allen", role = "aut"),
|
||||
person("Jonathan", "McPherson", role = "aut", email = "jonathan@posit.co"),
|
||||
person("Alan", "Dipert", role = "aut"),
|
||||
person("Barbara", "Borges", role = "aut"),
|
||||
person(family = "RStudio", role = "cph"),
|
||||
person("Posit Software, PBC", role = c("cph", "fnd")),
|
||||
person(family = "jQuery Foundation", role = "cph",
|
||||
comment = "jQuery library and jQuery UI library"),
|
||||
person(family = "jQuery contributors", role = c("ctb", "cph"),
|
||||
@@ -111,7 +111,8 @@ Suggests:
|
||||
ragg,
|
||||
showtext,
|
||||
sass
|
||||
URL: https://shiny.rstudio.com/
|
||||
URL: https://shiny.posit.co/,
|
||||
https://github.com/rstudio/shiny
|
||||
BugReports: https://github.com/rstudio/shiny/issues
|
||||
Collate:
|
||||
'globals.R'
|
||||
|
||||
40
NEWS.md
40
NEWS.md
@@ -1,21 +1,45 @@
|
||||
# shiny 1.7.4.9002
|
||||
# shiny (development version)
|
||||
|
||||
## Full changelog
|
||||
## New features and improvements
|
||||
|
||||
### Breaking changes
|
||||
## Bug fixes
|
||||
|
||||
### New features and improvements
|
||||
* `fileInput()` no longer has unwanted round corners applied to the `buttonLabel`. (#3879)
|
||||
|
||||
* Closed #789: `<script>` loaded from dynamic UI are no longer loaded using synchronous `XMLHttpRequest` (via jQuery). (#3666)
|
||||
# shiny 1.7.5
|
||||
|
||||
## Possibly breaking changes
|
||||
|
||||
* For `reactiveValues()` objects, whenever the `$names()` or `$values()` methods are called, the keys are now returned in the order that they were inserted. (#3774)
|
||||
|
||||
* The value provided to `options(shiny.json.digits)` is now interpreted as number of _digits after the decimal_ instead of _significant digits_. To treat the value as significant digits, wrap it in `I()` (e.g., `options(shiny.json.digits = I(4))`). This new default behavior not only helps with reducing digits in testing snapshots, but is also more consistent with `{jsonlite}`'s default behavior. (#3819)
|
||||
|
||||
## New features and improvements
|
||||
|
||||
* Closed #789: Dynamic UI is now rendered asynchronously, thanks in part to the newly exported `Shiny.renderDependenciesAsync()`, `Shiny.renderHtmlAsync()`, and `Shiny.renderContentAsync()`. Importantly, this means `<script>` tags are now loaded asynchronously (the old way used `XMLHttpRequest`, which is synchronous). In addition, `Shiny` now manages a queue of async tasks (exposed via `Shiny.shinyapp.taskQueue`) so that order of execution is preserved. (#3666)
|
||||
|
||||
* Fixes #3840: `updateSliderInput()` now warns when attempting to set invalid `min`, `max`, or `value` values. Sending an invalid update message to an input no longer causes other update messages to fail. (#3843)
|
||||
|
||||
* `sliderInput()` now has a larger target area for clicking or tapping on the slider handle or range. (#3859)
|
||||
|
||||
* Closed #2956: Component authors can now prevent Shiny from creating an input binding on specific elements by adding the `data-shiny-no-bind-input` attribute to the element. The attribute may have any or no value; its presence will prevent binding. This feature is primarily useful for input component authors who want to use standard HTML input elements without causing Shiny to create an input binding for them. Additionally, Shiny now adds custom classes to its inputs. For example, `checkboxInput()` now has a `shiny-input-checkbox` class. These custom classes may be utilized in future updates to Shiny's input binding logic. (#3861)
|
||||
|
||||
* `Map` objects are now initialized at load time instead of build time. This avoids potential problems that could arise from storing `fastmap` objects into the built Shiny package. (#3775)
|
||||
|
||||
### Bug fixes
|
||||
## Bug fixes
|
||||
|
||||
* Fixed #3771: Sometimes the error `ion.rangeSlider.min.js: i.stopPropagation is not a function` would appear in the JavaScript console. (#3772)
|
||||
|
||||
* Fixed #3833: When `width` is provided to `textAreaInput()`, we now correctly set the width of the `<textarea>` element. (#3838)
|
||||
|
||||
|
||||
# shiny 1.7.4.1
|
||||
|
||||
## Full changelog
|
||||
|
||||
* Closed #3849: In R-devel, a warning was raised when Shiny was loaded because `as.numeric_version()` was called with a number instead of a string. (#3850)
|
||||
|
||||
|
||||
# shiny 1.7.4
|
||||
|
||||
## Full changelog
|
||||
@@ -165,7 +189,7 @@ This release focuses on improvements in three main areas:
|
||||
|
||||
1. Better theming (and Bootstrap 4) support:
|
||||
* The `theme` argument of `fluidPage()`, `navbarPage()`, and `bootstrapPage()` all now understand `bslib::bs_theme()` objects, which can be used to opt-into Bootstrap 4, use any Bootswatch theme, and/or implement custom themes without writing any CSS.
|
||||
* The `session` object now includes `$setCurrentTheme()` and `$getCurrentTheme()` methods to dynamically update (or obtain) the page's `theme` after initial load, which is useful for things such as [adding a dark mode switch to an app](https://rstudio.github.io/bslib/articles/bslib.html#dynamic) or some other "real-time" theming tool like `bslib::bs_themer()`.
|
||||
* The `session` object now includes `$setCurrentTheme()` and `$getCurrentTheme()` methods to dynamically update (or obtain) the page's `theme` after initial load, which is useful for things such as [adding a dark mode switch to an app](https://rstudio.github.io/bslib/articles/theming.html#dynamic) or some other "real-time" theming tool like `bslib::bs_themer()`.
|
||||
* For more details, see [`{bslib}`'s website](https://rstudio.github.io/bslib/)
|
||||
|
||||
2. Caching of `reactive()` and `render*()` (e.g. `renderText()`, `renderTable()`, etc) expressions.
|
||||
@@ -558,7 +582,7 @@ This is a significant release for Shiny, with a major new feature that was nearl
|
||||
|
||||
* Fixed #1600: URL-encoded bookmarking did not work with sliders that had dates or date-times. (#1961)
|
||||
|
||||
* Fixed #1962: [File dragging and dropping](https://www.rstudio.com/blog/shiny-1-0-4/) broke in the presence of jQuery version 3.0 as introduced by the [rhandsontable](https://jrowen.github.io/rhandsontable/) [htmlwidget](https://www.htmlwidgets.org/). (#2005)
|
||||
* Fixed #1962: [File dragging and dropping](https://posit.co/blog/shiny-1-0-4/) broke in the presence of jQuery version 3.0 as introduced by the [rhandsontable](https://jrowen.github.io/rhandsontable/) [htmlwidget](https://www.htmlwidgets.org/). (#2005)
|
||||
|
||||
* Improved the error handling inside the `addResourcePath()` function, to give end users more informative error messages when the `directoryPath` argument cannot be normalized. This is especially useful for `runtime: shiny_prerendered` Rmd documents, like `learnr` tutorials. (#1968)
|
||||
|
||||
|
||||
@@ -159,8 +159,8 @@ utils::globalVariables(".GenericCallEnv", add = TRUE)
|
||||
#' ```
|
||||
#'
|
||||
#' To use different settings for a session-scoped cache, you can set
|
||||
#' `self$cache` at the top of your server function. By default, it will create
|
||||
#' a 200 MB memory cache for each session, but you can replace it with
|
||||
#' `session$cache` at the top of your server function. By default, it will
|
||||
#' create a 200 MB memory cache for each session, but you can replace it with
|
||||
#' something different. To use the session-scoped cache, you must also call
|
||||
#' `bindCache()` with `cache="session"`. This will create a 100 MB cache for
|
||||
#' the session:
|
||||
|
||||
@@ -374,8 +374,7 @@ collapseSizes <- function(padding) {
|
||||
#' @param inverse `TRUE` to use a dark background and light text for the
|
||||
#' navigation bar
|
||||
#' @param collapsible `TRUE` to automatically collapse the navigation
|
||||
#' elements into a menu when the width of the browser is less than 940 pixels
|
||||
#' (useful for viewing on smaller touchscreen device)
|
||||
#' elements into an expandable menu on mobile devices or narrow window widths.
|
||||
#' @param fluid `TRUE` to use a fluid layout. `FALSE` to use a fixed
|
||||
#' layout.
|
||||
#' @param windowTitle the browser window title (as a character string). The
|
||||
@@ -1200,19 +1199,25 @@ uiOutput <- htmlOutput
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' ui <- fluidPage(
|
||||
#' p("Choose a dataset to download."),
|
||||
#' selectInput("dataset", "Dataset", choices = c("mtcars", "airquality")),
|
||||
#' downloadButton("downloadData", "Download")
|
||||
#' )
|
||||
#'
|
||||
#' server <- function(input, output) {
|
||||
#' # Our dataset
|
||||
#' data <- mtcars
|
||||
#' # The requested dataset
|
||||
#' data <- reactive({
|
||||
#' get(input$dataset)
|
||||
#' })
|
||||
#'
|
||||
#' output$downloadData <- downloadHandler(
|
||||
#' filename = function() {
|
||||
#' paste("data-", Sys.Date(), ".csv", sep="")
|
||||
#' # Use the selected dataset as the suggested file name
|
||||
#' paste0(input$dataset, ".csv")
|
||||
#' },
|
||||
#' content = function(file) {
|
||||
#' write.csv(data, file)
|
||||
#' # Write the dataset to the `file` that will be downloaded
|
||||
#' write.csv(data(), file)
|
||||
#' }
|
||||
#' )
|
||||
#' }
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
s3_register("knitr::knit_print", "reactive")
|
||||
s3_register("knitr::knit_print", "shiny.appobj")
|
||||
s3_register("knitr::knit_print", "shiny.render.function")
|
||||
|
||||
# Shiny 1.4.0 bumps jQuery 1.x to 3.x, which caused a problem
|
||||
# with static-rendering of htmlwidgets, and htmlwidgets 1.5
|
||||
# includes a fix for this problem
|
||||
# https://github.com/rstudio/shiny/issues/2630
|
||||
register_upgrade_message("htmlwidgets", 1.5)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ checkboxInput <- function(inputId, label, value = FALSE, width = NULL) {
|
||||
|
||||
value <- restoreInput(id = inputId, default = value)
|
||||
|
||||
inputTag <- tags$input(id = inputId, type="checkbox")
|
||||
inputTag <- tags$input(id = inputId, type="checkbox", class = "shiny-input-checkbox")
|
||||
if (!is.null(value) && value)
|
||||
inputTag$attribs$checked <- "checked"
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ fileInput <- function(inputId, label, multiple = FALSE, accept = NULL,
|
||||
|
||||
inputTag <- tags$input(
|
||||
id = inputId,
|
||||
class = "shiny-input-file",
|
||||
name = inputId,
|
||||
type = "file",
|
||||
# Don't use "display: none;" style, which causes keyboard accessibility issue; instead use the following workaround: https://css-tricks.com/places-its-tempting-to-use-display-none-but-dont/
|
||||
|
||||
@@ -35,7 +35,7 @@ numericInput <- function(inputId, label, value, min = NA, max = NA, step = NA,
|
||||
value <- restoreInput(id = inputId, default = value)
|
||||
|
||||
# build input tag
|
||||
inputTag <- tags$input(id = inputId, type = "number", class="form-control",
|
||||
inputTag <- tags$input(id = inputId, type = "number", class="shiny-input-number form-control",
|
||||
value = formatNoSci(value))
|
||||
if (!is.na(min))
|
||||
inputTag$attribs$min = min
|
||||
|
||||
@@ -35,7 +35,7 @@ passwordInput <- function(inputId, label, value = "", width = NULL,
|
||||
div(class = "form-group shiny-input-container",
|
||||
style = css(width = validateCssUnit(width)),
|
||||
shinyInputLabel(inputId, label),
|
||||
tags$input(id = inputId, type="password", class="form-control", value=value,
|
||||
tags$input(id = inputId, type="password", class="shiny-input-password form-control", value=value,
|
||||
placeholder = placeholder)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#' from a list of values.
|
||||
#'
|
||||
#' By default, `selectInput()` and `selectizeInput()` use the JavaScript library
|
||||
#' \pkg{selectize.js} (<https://github.com/selectize/selectize.js>) instead of
|
||||
#' \pkg{selectize.js} (<https://selectize.dev/) instead of
|
||||
#' the basic select input element. To use the standard HTML select input
|
||||
#' element, use `selectInput()` with `selectize=FALSE`.
|
||||
#'
|
||||
@@ -106,6 +106,7 @@ selectInput <- function(inputId, label, choices, selected = NULL,
|
||||
# create select tag and add options
|
||||
selectTag <- tags$select(
|
||||
id = inputId,
|
||||
class = "shiny-input-select",
|
||||
class = if (!selectize) "form-control",
|
||||
size = size,
|
||||
selectOptions(choices, selected, inputId, selectize)
|
||||
@@ -172,7 +173,7 @@ needOptgroup <- function(choices) {
|
||||
|
||||
#' @rdname selectInput
|
||||
#' @param ... Arguments passed to `selectInput()`.
|
||||
#' @param options A list of options. See the documentation of \pkg{selectize.js}
|
||||
#' @param options A list of options. See the documentation of \pkg{selectize.js}(<https://selectize.dev/docs/usage>)
|
||||
#' for possible options (character option values inside [base::I()] will
|
||||
#' be treated as literal JavaScript code; see [renderDataTable()]
|
||||
#' for details).
|
||||
@@ -287,7 +288,7 @@ selectizeStaticDependency <- function(version) {
|
||||
#'
|
||||
#' By default, `varSelectInput()` and `selectizeInput()` use the
|
||||
#' JavaScript library \pkg{selectize.js}
|
||||
#' (<https://github.com/selectize/selectize.js>) to instead of the basic
|
||||
#' (<https://selectize.dev/>) to instead of the basic
|
||||
#' select input element. To use the standard HTML select input element, use
|
||||
#' `selectInput()` with `selectize=FALSE`.
|
||||
#'
|
||||
@@ -383,7 +384,7 @@ varSelectInput <- function(
|
||||
|
||||
#' @rdname varSelectInput
|
||||
#' @param ... Arguments passed to `varSelectInput()`.
|
||||
#' @param options A list of options. See the documentation of \pkg{selectize.js}
|
||||
#' @param options A list of options. See the documentation of \pkg{selectize.js}(<https://selectize.dev/docs/usage>)
|
||||
#' for possible options (character option values inside [base::I()] will
|
||||
#' be treated as literal JavaScript code; see [renderDataTable()]
|
||||
#' for details).
|
||||
|
||||
@@ -42,7 +42,7 @@ textInput <- function(inputId, label, value = "", width = NULL,
|
||||
div(class = "form-group shiny-input-container",
|
||||
style = css(width = validateCssUnit(width)),
|
||||
shinyInputLabel(inputId, label),
|
||||
tags$input(id = inputId, type="text", class="form-control", value=value,
|
||||
tags$input(id = inputId, type="text", class="shiny-input-text form-control", value=value,
|
||||
placeholder = placeholder)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
|
||||
|
||||
style <- css(
|
||||
# The width is specified on the parent div.
|
||||
width = if (!is.null(width)) "width: 100%;",
|
||||
width = if (!is.null(width)) "100%",
|
||||
height = validateCssUnit(height),
|
||||
resize = resize
|
||||
)
|
||||
@@ -62,7 +62,7 @@ textAreaInput <- function(inputId, label, value = "", width = NULL, height = NUL
|
||||
style = if (!is.null(width)) paste0("width: ", validateCssUnit(width), ";"),
|
||||
tags$textarea(
|
||||
id = inputId,
|
||||
class = "form-control",
|
||||
class = "shiny-input-textarea form-control",
|
||||
placeholder = placeholder,
|
||||
style = style,
|
||||
rows = rows,
|
||||
|
||||
8
R/map.R
8
R/map.R
@@ -48,9 +48,9 @@ Map <- R6Class(
|
||||
)
|
||||
)
|
||||
|
||||
as.list.Map <- function(map) {
|
||||
map$values()
|
||||
as.list.Map <- function(x, ...) {
|
||||
x$values()
|
||||
}
|
||||
length.Map <- function(map) {
|
||||
map$size()
|
||||
length.Map <- function(x) {
|
||||
x$size()
|
||||
}
|
||||
|
||||
@@ -2187,8 +2187,8 @@ maskReactiveContext <- function(expr) {
|
||||
#' @param autoDestroy If `TRUE` (the default), the observer will be
|
||||
#' automatically destroyed when its domain (if any) ends.
|
||||
#' @param ignoreNULL Whether the action should be triggered (or value
|
||||
#' calculated, in the case of `eventReactive`) when the input is
|
||||
#' `NULL`. See Details.
|
||||
#' calculated, in the case of `eventReactive`) when the input event expression
|
||||
#' is `NULL`. See Details.
|
||||
#' @param ignoreInit If `TRUE`, then, when this `observeEvent` is
|
||||
#' first created/initialized, ignore the `handlerExpr` (the second
|
||||
#' argument), whether it is otherwise supposed to run or not. The default is
|
||||
|
||||
@@ -90,8 +90,9 @@ getShinyOption <- function(name, default = NULL) {
|
||||
#' \item{shiny.jquery.version (defaults to `3`)}{The major version of jQuery to use.
|
||||
#' Currently only values of `3` or `1` are supported. If `1`, then jQuery 1.12.4 is used. If `3`,
|
||||
#' then jQuery `r version_jquery` is used.}
|
||||
#' \item{shiny.json.digits (defaults to `16`)}{The number of digits to use when converting
|
||||
#' numbers to JSON format to send to the client web browser.}
|
||||
#' \item{shiny.json.digits (defaults to `I(16)`)}{Max number of digits to use when converting
|
||||
#' numbers to JSON format to send to the client web browser. Use [I()] to specify significant digits.
|
||||
#' Use `NA` for max precision.}
|
||||
#' \item{shiny.launch.browser (defaults to `interactive()`)}{A boolean which controls the default behavior
|
||||
#' when an app is run. See [runApp()] for more information.}
|
||||
#' \item{shiny.mathjax.url (defaults to `"https://mathjax.rstudio.com/latest/MathJax.js"`)}{
|
||||
|
||||
@@ -34,3 +34,11 @@ NULL
|
||||
# since we call require(shiny) as part of loading the app.
|
||||
#' @import methods
|
||||
NULL
|
||||
|
||||
|
||||
# For usethis::use_release_issue()
|
||||
release_bullets <- function() {
|
||||
c(
|
||||
"Update static imports: `staticimports::import()`"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,8 +33,12 @@ createUniqueId <- function(bytes, prefix = "", suffix = "") {
|
||||
}
|
||||
|
||||
toJSON <- function(x, ..., dataframe = "columns", null = "null", na = "null",
|
||||
auto_unbox = TRUE, digits = getOption("shiny.json.digits", 16),
|
||||
use_signif = TRUE, force = TRUE, POSIXt = "ISO8601", UTC = TRUE,
|
||||
auto_unbox = TRUE,
|
||||
# Shiny has had a legacy value of 16 significant digits
|
||||
# We can use `I(16)` mixed with the default behavior in jsonlite's `use_signif=`
|
||||
# https://github.com/jeroen/jsonlite/commit/728efa9
|
||||
digits = getOption("shiny.json.digits", I(16)), use_signif = is(digits, "AsIs"),
|
||||
force = TRUE, POSIXt = "ISO8601", UTC = TRUE,
|
||||
rownames = FALSE, keep_vec_names = TRUE, strict_atomic = TRUE) {
|
||||
|
||||
if (strict_atomic) {
|
||||
|
||||
@@ -42,36 +42,20 @@ get_package_version <- function(pkg) {
|
||||
|
||||
is_installed <- function(pkg, version = NULL) {
|
||||
installed <- isNamespaceLoaded(pkg) || nzchar(system_file_cached(package = pkg))
|
||||
|
||||
if (is.null(version)) {
|
||||
return(installed)
|
||||
}
|
||||
installed && isTRUE(get_package_version(pkg) >= version)
|
||||
}
|
||||
|
||||
register_upgrade_message <- function(pkg, version, error = FALSE) {
|
||||
if (!is.character(version) && !inherits(version, "numeric_version")) {
|
||||
# Avoid https://bugs.r-project.org/show_bug.cgi?id=18548
|
||||
alert <- if (identical(Sys.getenv("TESTTHAT"), "true")) stop else warning
|
||||
alert("`version` must be a character string or a `package_version` or `numeric_version` object.")
|
||||
|
||||
msg <- sprintf(
|
||||
"This version of '%s' is designed to work with '%s' >= %s.
|
||||
Please upgrade via install.packages('%s').",
|
||||
environmentName(environment(register_upgrade_message)),
|
||||
pkg, version, pkg
|
||||
)
|
||||
|
||||
cond <- if (error) stop else packageStartupMessage
|
||||
|
||||
if (pkg %in% loadedNamespaces() && !is_installed(pkg, version)) {
|
||||
cond(msg)
|
||||
version <- numeric_version(sprintf("%0.9g", version))
|
||||
}
|
||||
|
||||
# Always register hook in case pkg is loaded at some
|
||||
# point the future (or, potentially, but less commonly,
|
||||
# unloaded & reloaded)
|
||||
setHook(
|
||||
packageEvent(pkg, "onLoad"),
|
||||
function(...) {
|
||||
if (!is_installed(pkg, version)) cond(msg)
|
||||
}
|
||||
)
|
||||
installed && isTRUE(get_package_version(pkg) >= version)
|
||||
}
|
||||
|
||||
# Simplified version rlang:::s3_register() that just uses
|
||||
@@ -190,11 +174,9 @@ system_file <- function(..., package = "base") {
|
||||
normalizePath(files, winslash = "/")
|
||||
}
|
||||
|
||||
# A wrapper for `system.file()`, which caches the results, because
|
||||
# `system.file()` can be slow. Note that because of caching, if
|
||||
# `system_file_cached()` is called on a package that isn't installed, then the
|
||||
# package is installed, and then `system_file_cached()` is called again, it will
|
||||
# still return "".
|
||||
# A wrapper for `system.file()`, which caches the package path because
|
||||
# `system.file()` can be slow. If a package is not installed, the result won't
|
||||
# be cached.
|
||||
system_file_cached <- local({
|
||||
pkg_dir_cache <- character()
|
||||
|
||||
@@ -206,7 +188,9 @@ system_file_cached <- local({
|
||||
not_cached <- is.na(match(package, names(pkg_dir_cache)))
|
||||
if (not_cached) {
|
||||
pkg_dir <- system.file(package = package)
|
||||
pkg_dir_cache[[package]] <<- pkg_dir
|
||||
if (nzchar(pkg_dir)) {
|
||||
pkg_dir_cache[[package]] <<- pkg_dir
|
||||
}
|
||||
} else {
|
||||
pkg_dir <- pkg_dir_cache[[package]]
|
||||
}
|
||||
|
||||
@@ -423,6 +423,23 @@ updateSliderInput <- function(session = getDefaultReactiveDomain(), inputId, lab
|
||||
{
|
||||
validate_session_object(session)
|
||||
|
||||
if (!is.null(value)) {
|
||||
if (!is.null(min) && !is.null(max)) {
|
||||
# Validate value/min/max together if all three are provided
|
||||
tryCatch(
|
||||
validate_slider_value(min, max, value, "updateSliderInput"),
|
||||
error = function(err) warning(conditionMessage(err), call. = FALSE)
|
||||
)
|
||||
} else if (length(value) < 1 || length(value) > 2 || any(is.na(value))) {
|
||||
# Otherwise ensure basic assumptions about value are met
|
||||
warning(
|
||||
"In updateSliderInput(): value must be a single value or a length-2 ",
|
||||
"vector and cannot contain NA values.",
|
||||
call. = FALSE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# If no min/max/value is provided, we won't know the
|
||||
# type, and this will return an empty string
|
||||
dataType <- getSliderType(min, max, value)
|
||||
|
||||
@@ -4,7 +4,7 @@ NULL
|
||||
|
||||
# @staticimports pkg:staticimports
|
||||
# is_installed get_package_version system_file
|
||||
# s3_register register_upgrade_message
|
||||
# s3_register
|
||||
# any_named any_unnamed
|
||||
|
||||
#' Make a random number generator repeatable
|
||||
|
||||
@@ -16,7 +16,7 @@ Easily build rich and productive interactive web apps in R — no HTML/CSS/J
|
||||
* A prebuilt set of highly sophisticated, customizable, and easy-to-use widgets (e.g., plots, tables, sliders, dropdowns, date pickers, and more).
|
||||
* An attractive default look based on [Bootstrap](https://getbootstrap.com/) which can also be easily customized with the [bslib](https://github.com/rstudio/bslib) package or avoided entirely with more direct R bindings to HTML/CSS/JavaScript.
|
||||
* Seamless integration with [R Markdown](https://shiny.rstudio.com/articles/interactive-docs.html), making it easy to embed numerous applications natively within a larger dynamic document.
|
||||
* Tools for improving and monitoring performance, including native support for [async programming](https://www.rstudio.com/blog/shiny-1-1-0/), [caching](https://talks.cpsievert.me/20201117), [load testing](https://rstudio.github.io/shinyloadtest/), and more.
|
||||
* Tools for improving and monitoring performance, including native support for [async programming](https://posit.co/blog/shiny-1-1-0/), [caching](https://talks.cpsievert.me/20201117), [load testing](https://rstudio.github.io/shinyloadtest/), and more.
|
||||
* [Modules](https://shiny.rstudio.com/articles/modules.html): a framework for reducing code duplication and complexity.
|
||||
* An ability to [bookmark application state](https://shiny.rstudio.com/articles/bookmarking-state.html) and/or [generate code to reproduce output(s)](https://github.com/rstudio/shinymeta).
|
||||
* A rich ecosystem of extension packages for more [custom widgets](http://www.htmlwidgets.org/), [input validation](https://github.com/rstudio/shinyvalidate), [unit testing](https://github.com/rstudio/shinytest), and more.
|
||||
@@ -45,6 +45,10 @@ For more examples and inspiration, check out the [Shiny User Gallery](https://sh
|
||||
|
||||
For help with learning fundamental Shiny programming concepts, check out the [Mastering Shiny](https://mastering-shiny.org/) book and the [Shiny Tutorial](https://shiny.rstudio.com/tutorial/). The former is currently more up-to-date with modern Shiny features, whereas the latter takes a deeper, more visual, dive into fundamental concepts.
|
||||
|
||||
## Join the conversation
|
||||
|
||||
If you want to chat about Shiny, meet other developers, or help us decide what to work on next, [join us on Discord](https://discord.com/invite/yMGCamUMnS).
|
||||
|
||||
## Getting Help
|
||||
|
||||
To ask a question about Shiny, please use the [RStudio Community website](https://community.rstudio.com/new-topic?category=shiny&tags=shiny).
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@charset "UTF-8";
|
||||
/* 'shiny' skin for Ion.RangeSlider, largely based on the 'big' skin, but with smaller dimensions, grayscale grid text, and without gradients
|
||||
© Posit, PBC, 2023
|
||||
© RStudio, Inc, 2014
|
||||
© Denis Ineshin, 2014 https://github.com/IonDen
|
||||
© guybowden, 2014 https://github.com/guybowden
|
||||
@@ -174,6 +175,18 @@
|
||||
background-color: #ededed;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 8px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-line::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: relative;
|
||||
cursor: s-resize;
|
||||
width: 100%;
|
||||
height: 22px;
|
||||
top: -9px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-bar {
|
||||
@@ -182,12 +195,24 @@
|
||||
border-top: 1px solid #428bca;
|
||||
border-bottom: 1px solid #428bca;
|
||||
background: #428bca;
|
||||
cursor: s-resize;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-bar--single {
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-bar::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 22px;
|
||||
top: -9px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-shadow {
|
||||
top: 38px;
|
||||
height: 2px;
|
||||
@@ -207,6 +232,7 @@
|
||||
background-color: #dedede;
|
||||
box-shadow: 1px 1px 3px rgba(255, 255, 255, 0.3);
|
||||
border-radius: 22px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.irs--shiny .irs-handle.state_hover, .irs--shiny .irs-handle:hover {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* 'shiny' skin for Ion.RangeSlider, largely based on the 'big' skin, but with smaller dimensions, grayscale grid text, and without gradients
|
||||
© Posit, PBC, 2023
|
||||
© RStudio, Inc, 2014
|
||||
© Denis Ineshin, 2014 https://github.com/IonDen
|
||||
© guybowden, 2014 https://github.com/guybowden
|
||||
@@ -79,6 +80,19 @@ $font-family: $font-family-base !default;
|
||||
background-color: $line_bg_color;
|
||||
border: $line_border;
|
||||
@include border-radius-shim($line_height);
|
||||
|
||||
// Increase the touch target area of the slider line
|
||||
overflow: visible;
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: relative;
|
||||
cursor: s-resize; // downward arrow
|
||||
width: 100%;
|
||||
height: $handle_height;
|
||||
top: -(($handle_height - $line_height / 2) / 2);
|
||||
z-index: 1; // raise touch area above grid
|
||||
}
|
||||
}
|
||||
|
||||
.#{$name}-bar {
|
||||
@@ -87,10 +101,23 @@ $font-family: $font-family-base !default;
|
||||
border-top: 1px solid $bar_color;
|
||||
border-bottom: 1px solid $bar_color;
|
||||
background: $bar_color;
|
||||
cursor: s-resize; // downard arrow, overwritten when a range
|
||||
z-index: 2;
|
||||
|
||||
&--single {
|
||||
@include border-radius-shim($line_height 0 0 $line_height);
|
||||
}
|
||||
|
||||
// Increase the touch target area of the slider bar
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: $handle_height;
|
||||
top: -(($handle_height - $line_height / 2) / 2);
|
||||
z-index: 2; // raise touch area above line touch target
|
||||
}
|
||||
}
|
||||
|
||||
// sliderInput() doesn't currently support from_min/from_max, so this isn't relevant
|
||||
@@ -114,6 +141,7 @@ $font-family: $font-family-base !default;
|
||||
background-color: $handle_color;
|
||||
box-shadow: $handle_box_shadow;
|
||||
border-radius: $handle_width;
|
||||
z-index: 2;
|
||||
|
||||
&.state_hover,
|
||||
&:hover {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
/*! shiny 1.7.4.9002 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.7.5.9000 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
#showcase-well{border-radius:0}.shiny-code{background-color:#fff;margin-bottom:0}.shiny-code code{font-family:Menlo,Consolas,Courier New,monospace}.shiny-code-container{margin-top:20px;clear:both}.shiny-code-container h3{display:inline;margin-right:15px}.showcase-header{font-size:16px;font-weight:400}.showcase-code-link{text-align:right;padding:15px}#showcase-app-container{vertical-align:top}#showcase-code-tabs{margin-right:15px}#showcase-code-tabs pre{border:none;line-height:1em}#showcase-code-tabs .nav,#showcase-code-tabs ul{margin-bottom:0}#showcase-code-tabs .tab-content{border-style:solid;border-color:#e5e5e5;border-width:0px 1px 1px 1px;overflow:auto;border-bottom-right-radius:4px;border-bottom-left-radius:4px}#showcase-app-code{width:100%}#showcase-code-position-toggle{float:right}#showcase-sxs-code{padding-top:20px;vertical-align:top}.showcase-code-license{display:block;text-align:right}#showcase-code-content pre{background-color:#fff}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
|
||||
/*! shiny 1.7.4.9002 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.7.5.9000 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
"use strict";(function(){var a=eval;window.addEventListener("message",function(i){var e=i.data;e.code&&a(e.code)});})();
|
||||
//# sourceMappingURL=shiny-testmode.js.map
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*! shiny 1.7.4.9002 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
/*! shiny 1.7.5.9000 | (c) 2012-2023 RStudio, PBC. | License: GPL-3 | file LICENSE */
|
||||
"use strict";
|
||||
(function() {
|
||||
var __create = Object.create;
|
||||
@@ -8241,7 +8241,8 @@
|
||||
msg.to = data.value[1];
|
||||
} else {
|
||||
if (Array.isArray(data.value)) {
|
||||
throw "Slider only contains a single value and cannot be updated with an array";
|
||||
var errorReason = ["an empty array.", "a single-value array.", "an array with more than two values."];
|
||||
throw "Slider requires two values to update with an array, but message value was " + errorReason[Math.min(data.value.length, 2)];
|
||||
}
|
||||
msg.from = data.value;
|
||||
}
|
||||
@@ -15583,7 +15584,7 @@
|
||||
if (opts.priority === "event") {
|
||||
this._sendNow();
|
||||
} else if (!this.sendIsEnqueued) {
|
||||
this.shinyapp.actionQueue.enqueue(function() {
|
||||
this.shinyapp.taskQueue.enqueue(function() {
|
||||
_this.sendIsEnqueued = false;
|
||||
_this._sendNow();
|
||||
});
|
||||
@@ -16567,6 +16568,8 @@
|
||||
var matches = binding.find(scope) || [];
|
||||
var _loop22 = function _loop23() {
|
||||
var el = matches[j];
|
||||
if (el.hasAttribute("data-shiny-no-bind-input"))
|
||||
return "continue";
|
||||
var id = binding.getId(el);
|
||||
if (!id || boundInputs[id])
|
||||
return "continue";
|
||||
@@ -17666,7 +17669,7 @@
|
||||
function ShinyApp2() {
|
||||
_classCallCheck36(this, ShinyApp2);
|
||||
_defineProperty18(this, "$socket", null);
|
||||
_defineProperty18(this, "actionQueue", new AsyncQueue());
|
||||
_defineProperty18(this, "taskQueue", new AsyncQueue());
|
||||
_defineProperty18(this, "config", null);
|
||||
_defineProperty18(this, "$inputValues", {});
|
||||
_defineProperty18(this, "$initialInput", null);
|
||||
@@ -17875,7 +17878,7 @@
|
||||
_this.startActionQueueLoop();
|
||||
};
|
||||
socket.onmessage = function(e) {
|
||||
_this.actionQueue.enqueue(/* @__PURE__ */ _asyncToGenerator8(/* @__PURE__ */ _regeneratorRuntime8().mark(function _callee2() {
|
||||
_this.taskQueue.enqueue(/* @__PURE__ */ _asyncToGenerator8(/* @__PURE__ */ _regeneratorRuntime8().mark(function _callee2() {
|
||||
return _regeneratorRuntime8().wrap(function _callee2$(_context2) {
|
||||
while (1)
|
||||
switch (_context2.prev = _context2.next) {
|
||||
@@ -17918,7 +17921,7 @@
|
||||
break;
|
||||
}
|
||||
_context3.next = 3;
|
||||
return this.actionQueue.dequeue();
|
||||
return this.taskQueue.dequeue();
|
||||
case 3:
|
||||
action = _context3.sent;
|
||||
_context3.prev = 4;
|
||||
@@ -18337,8 +18340,17 @@
|
||||
evt.message = message[i].message;
|
||||
evt.binding = inputBinding;
|
||||
(0, import_jquery38.default)(el).trigger(evt);
|
||||
if (!evt.isDefaultPrevented())
|
||||
inputBinding.receiveMessage(el, evt.message);
|
||||
if (!evt.isDefaultPrevented()) {
|
||||
try {
|
||||
inputBinding.receiveMessage(el, evt.message);
|
||||
} catch (error) {
|
||||
console.error("[shiny] Error in inputBinding.receiveMessage()", {
|
||||
error: error,
|
||||
binding: inputBinding,
|
||||
message: evt.message
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -19184,7 +19196,7 @@
|
||||
var windowShiny2;
|
||||
function setShiny(windowShiny_) {
|
||||
windowShiny2 = windowShiny_;
|
||||
windowShiny2.version = "1.7.4.9002";
|
||||
windowShiny2.version = "1.7.5.9000";
|
||||
var _initInputBindings = initInputBindings(), inputBindings = _initInputBindings.inputBindings, fileInputBinding2 = _initInputBindings.fileInputBinding;
|
||||
var _initOutputBindings = initOutputBindings(), outputBindings = _initOutputBindings.outputBindings;
|
||||
setFileInputBinding(fileInputBinding2);
|
||||
|
||||
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.css
vendored
4
inst/www/shared/shiny.min.css
vendored
File diff suppressed because one or more lines are too long
4
inst/www/shared/shiny.min.js
vendored
4
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -157,6 +157,9 @@ pre.shiny-text-output {
|
||||
margin-top: -9px;
|
||||
}
|
||||
.slider-animate-button {
|
||||
/* Ensure controls above slider line touch target */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
opacity: 0.5;
|
||||
.pause {
|
||||
display: none;
|
||||
@@ -181,6 +184,12 @@ pre.shiny-text-output {
|
||||
}
|
||||
}
|
||||
|
||||
// fileInput()'s button should never have a top-right or bottom-right border-radius
|
||||
.btn-file {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* Make sure the filename doesn't extend past the bounds of the container */
|
||||
.shiny-input-container input[type=file] {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -166,8 +166,8 @@ instead of the default 200 MB:
|
||||
}\if{html}{\out{</div>}}
|
||||
|
||||
To use different settings for a session-scoped cache, you can set
|
||||
\code{self$cache} at the top of your server function. By default, it will create
|
||||
a 200 MB memory cache for each session, but you can replace it with
|
||||
\code{session$cache} at the top of your server function. By default, it will
|
||||
create a 200 MB memory cache for each session, but you can replace it with
|
||||
something different. To use the session-scoped cache, you must also call
|
||||
\code{bindCache()} with \code{cache="session"}. This will create a 100 MB cache for
|
||||
the session:
|
||||
|
||||
@@ -36,19 +36,25 @@ function.
|
||||
\examples{
|
||||
\dontrun{
|
||||
ui <- fluidPage(
|
||||
p("Choose a dataset to download."),
|
||||
selectInput("dataset", "Dataset", choices = c("mtcars", "airquality")),
|
||||
downloadButton("downloadData", "Download")
|
||||
)
|
||||
|
||||
server <- function(input, output) {
|
||||
# Our dataset
|
||||
data <- mtcars
|
||||
# The requested dataset
|
||||
data <- reactive({
|
||||
get(input$dataset)
|
||||
})
|
||||
|
||||
output$downloadData <- downloadHandler(
|
||||
filename = function() {
|
||||
paste("data-", Sys.Date(), ".csv", sep="")
|
||||
# Use the selected dataset as the suggested file name
|
||||
paste0(input$dataset, ".csv")
|
||||
},
|
||||
content = function(file) {
|
||||
write.csv(data, file)
|
||||
# Write the dataset to the `file` that will be downloaded
|
||||
write.csv(data(), file)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -58,8 +58,7 @@ tabPanels}
|
||||
navigation bar}
|
||||
|
||||
\item{collapsible}{\code{TRUE} to automatically collapse the navigation
|
||||
elements into a menu when the width of the browser is less than 940 pixels
|
||||
(useful for viewing on smaller touchscreen device)}
|
||||
elements into an expandable menu on mobile devices or narrow window widths.}
|
||||
|
||||
\item{fluid}{\code{TRUE} to use a fluid layout. \code{FALSE} to use a fixed
|
||||
layout.}
|
||||
|
||||
@@ -86,8 +86,8 @@ Positive, negative, and zero values are allowed.}
|
||||
automatically destroyed when its domain (if any) ends.}
|
||||
|
||||
\item{ignoreNULL}{Whether the action should be triggered (or value
|
||||
calculated, in the case of \code{eventReactive}) when the input is
|
||||
\code{NULL}. See Details.}
|
||||
calculated, in the case of \code{eventReactive}) when the input event expression
|
||||
is \code{NULL}. See Details.}
|
||||
|
||||
\item{ignoreInit}{If \code{TRUE}, then, when this \code{observeEvent} is
|
||||
first created/initialized, ignore the \code{handlerExpr} (the second
|
||||
|
||||
@@ -48,7 +48,7 @@ but when \code{size} is set, it will be a box instead.}
|
||||
|
||||
\item{...}{Arguments passed to \code{selectInput()}.}
|
||||
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}(\url{https://selectize.dev/docs/usage})
|
||||
for possible options (character option values inside \code{\link[base:AsIs]{base::I()}} will
|
||||
be treated as literal JavaScript code; see \code{\link[=renderDataTable]{renderDataTable()}}
|
||||
for details).}
|
||||
@@ -62,7 +62,7 @@ from a list of values.
|
||||
}
|
||||
\details{
|
||||
By default, \code{selectInput()} and \code{selectizeInput()} use the JavaScript library
|
||||
\pkg{selectize.js} (\url{https://github.com/selectize/selectize.js}) instead of
|
||||
\pkg{selectize.js} (<https://selectize.dev/) instead of
|
||||
the basic select input element. To use the standard HTML select input
|
||||
element, use \code{selectInput()} with \code{selectize=FALSE}.
|
||||
|
||||
|
||||
@@ -69,8 +69,9 @@ be done 100\% correctly.}
|
||||
\item{shiny.jquery.version (defaults to \code{3})}{The major version of jQuery to use.
|
||||
Currently only values of \code{3} or \code{1} are supported. If \code{1}, then jQuery 1.12.4 is used. If \code{3},
|
||||
then jQuery 3.6.0 is used.}
|
||||
\item{shiny.json.digits (defaults to \code{16})}{The number of digits to use when converting
|
||||
numbers to JSON format to send to the client web browser.}
|
||||
\item{shiny.json.digits (defaults to \code{I(16)})}{Max number of digits to use when converting
|
||||
numbers to JSON format to send to the client web browser. Use \code{\link[=I]{I()}} to specify significant digits.
|
||||
Use \code{NA} for max precision.}
|
||||
\item{shiny.launch.browser (defaults to \code{interactive()})}{A boolean which controls the default behavior
|
||||
when an app is run. See \code{\link[=runApp]{runApp()}} for more information.}
|
||||
\item{shiny.mathjax.url (defaults to \code{"https://mathjax.rstudio.com/latest/MathJax.js"})}{
|
||||
|
||||
@@ -62,7 +62,7 @@ the example section for a small demo of this feature.}
|
||||
\item{selected}{The initially selected value (or multiple values if \code{multiple = TRUE}). If not specified then defaults to the first value for
|
||||
single-select lists and no values for multiple select lists.}
|
||||
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}(\url{https://selectize.dev/docs/usage})
|
||||
for possible options (character option values inside \code{\link[base:AsIs]{base::I()}} will
|
||||
be treated as literal JavaScript code; see \code{\link[=renderDataTable]{renderDataTable()}}
|
||||
for details).}
|
||||
|
||||
@@ -42,7 +42,7 @@ but when \code{size} is set, it will be a box instead.}
|
||||
|
||||
\item{...}{Arguments passed to \code{varSelectInput()}.}
|
||||
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}
|
||||
\item{options}{A list of options. See the documentation of \pkg{selectize.js}(\url{https://selectize.dev/docs/usage})
|
||||
for possible options (character option values inside \code{\link[base:AsIs]{base::I()}} will
|
||||
be treated as literal JavaScript code; see \code{\link[=renderDataTable]{renderDataTable()}}
|
||||
for details).}
|
||||
@@ -57,7 +57,7 @@ from the column names of a data frame.
|
||||
\details{
|
||||
By default, \code{varSelectInput()} and \code{selectizeInput()} use the
|
||||
JavaScript library \pkg{selectize.js}
|
||||
(\url{https://github.com/selectize/selectize.js}) to instead of the basic
|
||||
(\url{https://selectize.dev/}) to instead of the basic
|
||||
select input element. To use the standard HTML select input element, use
|
||||
\code{selectInput()} with \code{selectize=FALSE}.
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"homepage": "https://shiny.rstudio.com",
|
||||
"repository": "github:rstudio/shiny",
|
||||
"name": "@types/rstudio-shiny",
|
||||
"version": "1.7.4-alpha.9002",
|
||||
"version": "1.7.5-alpha.9000",
|
||||
"license": "GPL-3.0-only",
|
||||
"main": "",
|
||||
"browser": "",
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
# Revdeps
|
||||
|
||||
## Failed to check (5)
|
||||
## Failed to check (21)
|
||||
|
||||
|package |version |error |warning |note |
|
||||
|:----------|:-------|:-----|:-------|:----|
|
||||
|ctsem |3.6.0 |1 | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|ctsem |3.7.6 |1 | | |
|
||||
|disk.frame |0.8.2 |1 | | |
|
||||
|diveR |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|grandR |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|loon.shiny |? | | | |
|
||||
|NA |? | | | |
|
||||
|SSVS |? | | | |
|
||||
|NA |? | | | |
|
||||
|RQuantLib |0.4.18 |1 | | |
|
||||
|rstanarm |2.21.4 |1 | | |
|
||||
|NA |? | | | |
|
||||
|NA |? | | | |
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
## revdepcheck results
|
||||
|
||||
We checked 1039 reverse dependencies (1038 from CRAN + 1 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
We checked 1145 reverse dependencies (1131 from CRAN + 14 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package.
|
||||
|
||||
* We saw 0 new problems
|
||||
* We failed to check 4 packages
|
||||
* We failed to check 7 packages
|
||||
|
||||
Issues with CRAN packages are summarised below.
|
||||
|
||||
### Failed to check
|
||||
|
||||
* ctsem (NA)
|
||||
* disk.frame (NA)
|
||||
* diveR (NA)
|
||||
* grandR (NA)
|
||||
* loon.shiny (NA)
|
||||
* SSVS (NA)
|
||||
* RQuantLib (NA)
|
||||
* rstanarm (NA)
|
||||
|
||||
@@ -9,6 +9,7 @@ type CheckboxReceiveMessageData = { value?: CheckboxChecked; label?: string };
|
||||
|
||||
class CheckboxInputBinding extends InputBinding {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs also have .shiny-input-checkbox class
|
||||
return $(scope).find('input[type="checkbox"]');
|
||||
}
|
||||
getValue(el: CheckedHTMLElement): CheckboxChecked {
|
||||
|
||||
@@ -195,6 +195,7 @@ function fileInputBindingGetId(this: any, el: HTMLInputElement): string {
|
||||
|
||||
class FileInputBinding extends InputBinding {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs also have .shiny-input-file class
|
||||
return $(scope).find('input[type="file"]');
|
||||
}
|
||||
getId(el: HTMLInputElement): string {
|
||||
|
||||
@@ -20,6 +20,7 @@ function getLabelNode(el: NumberHTMLElement): JQuery<HTMLElement> {
|
||||
|
||||
class NumberInputBinding extends TextInputBindingBase {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs also have .shiny-input-number class
|
||||
return $(scope).find('input[type="number"]');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TextInputBinding } from "./text";
|
||||
|
||||
class PasswordInputBinding extends TextInputBinding {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs also have .shiny-input-password class
|
||||
return $(scope).find('input[type="password"]');
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ function isSelectize(el: HTMLElement): boolean {
|
||||
|
||||
class SelectInputBinding extends InputBinding {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs also have .shiny-input-select class
|
||||
return $(scope).find("select");
|
||||
}
|
||||
getType(el: HTMLElement): string | null {
|
||||
|
||||
@@ -197,7 +197,16 @@ class SliderInputBinding extends TextInputBindingBase {
|
||||
msg.to = data.value[1];
|
||||
} else {
|
||||
if (Array.isArray(data.value)) {
|
||||
throw "Slider only contains a single value and cannot be updated with an array";
|
||||
const errorReason = [
|
||||
"an empty array.",
|
||||
"a single-value array.",
|
||||
"an array with more than two values.",
|
||||
];
|
||||
throw (
|
||||
"Slider requires two values to update with an array, " +
|
||||
"but message value was " +
|
||||
errorReason[Math.min(data.value.length, 2)]
|
||||
);
|
||||
}
|
||||
msg.from = data.value;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ class TextInputBindingBase extends InputBinding {
|
||||
// id that ends in '-selectized'. The .not() selector below
|
||||
// is to prevent textInputBinding from accidentally picking up
|
||||
// this hidden element as a shiny input (#2396)
|
||||
|
||||
//
|
||||
// Inputs also now have .shiny-input-text class
|
||||
return $inputs.not('input[type="text"][id$="-selectized"]');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TextInputBinding } from "./text";
|
||||
|
||||
class TextareaInputBinding extends TextInputBinding {
|
||||
find(scope: HTMLElement): JQuery<HTMLElement> {
|
||||
// Inputs now also have the .shiny-input-textarea class
|
||||
return $(scope).find("textarea");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class InputBatchSender implements InputPolicy {
|
||||
if (opts.priority === "event") {
|
||||
this._sendNow();
|
||||
} else if (!this.sendIsEnqueued) {
|
||||
this.shinyapp.actionQueue.enqueue(() => {
|
||||
this.shinyapp.taskQueue.enqueue(() => {
|
||||
this.sendIsEnqueued = false;
|
||||
this._sendNow();
|
||||
});
|
||||
|
||||
@@ -82,6 +82,7 @@ function bindInputs(
|
||||
|
||||
for (let j = 0; j < matches.length; j++) {
|
||||
const el = matches[j];
|
||||
if (el.hasAttribute("data-shiny-no-bind-input")) continue;
|
||||
const id = binding.getId(el);
|
||||
|
||||
// Check if ID is falsy, or if already bound
|
||||
|
||||
@@ -114,7 +114,7 @@ class ShinyApp {
|
||||
// without overlapping. This is used for handling incoming messages from the
|
||||
// server and scheduling outgoing messages to the server, and can be used for
|
||||
// other things tasks as well.
|
||||
actionQueue = new AsyncQueue<() => Promise<void> | void>();
|
||||
taskQueue = new AsyncQueue<() => Promise<void> | void>();
|
||||
|
||||
config: {
|
||||
workerId: string;
|
||||
@@ -240,7 +240,7 @@ class ShinyApp {
|
||||
this.startActionQueueLoop();
|
||||
};
|
||||
socket.onmessage = (e) => {
|
||||
this.actionQueue.enqueue(async () => await this.dispatchMessage(e.data));
|
||||
this.taskQueue.enqueue(async () => await this.dispatchMessage(e.data));
|
||||
};
|
||||
// Called when a successfully-opened websocket is closed, or when an
|
||||
// attempt to open a connection fails.
|
||||
@@ -266,7 +266,7 @@ class ShinyApp {
|
||||
async startActionQueueLoop(): Promise<void> {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const action = await this.actionQueue.dequeue();
|
||||
const action = await this.taskQueue.dequeue();
|
||||
|
||||
try {
|
||||
await action();
|
||||
@@ -725,8 +725,16 @@ class ShinyApp {
|
||||
evt.message = message[i].message;
|
||||
evt.binding = inputBinding;
|
||||
$(el).trigger(evt);
|
||||
if (!evt.isDefaultPrevented())
|
||||
inputBinding.receiveMessage(el, evt.message);
|
||||
if (!evt.isDefaultPrevented()) {
|
||||
try {
|
||||
inputBinding.receiveMessage(el, evt.message);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[shiny] Error in inputBinding.receiveMessage()",
|
||||
{ error, binding: inputBinding, message: evt.message }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
srcts/types/src/shiny/shinyapp.d.ts
vendored
2
srcts/types/src/shiny/shinyapp.d.ts
vendored
@@ -20,7 +20,7 @@ type MessageValue = Parameters<WebSocket["send"]>[0];
|
||||
declare function addCustomMessageHandler(type: string, handler: Handler): void;
|
||||
declare class ShinyApp {
|
||||
$socket: ShinyWebSocket | null;
|
||||
actionQueue: AsyncQueue<() => Promise<void> | void>;
|
||||
taskQueue: AsyncQueue<() => Promise<void> | void>;
|
||||
config: {
|
||||
workerId: string;
|
||||
sessionId: string;
|
||||
|
||||
Submodule tests/testthat/apps deleted from c471e6449e
@@ -22,7 +22,7 @@ test_that("Repeated names for selectInput and radioButtons choices", {
|
||||
# Select input
|
||||
x <- selectInput('id','label', choices = c(a='x1', a='x2', b='x3'), selectize = FALSE)
|
||||
expect_true(grepl(fixed = TRUE,
|
||||
'<select id="id" class="form-control"><option value="x1" selected>a</option>\n<option value="x2">a</option>\n<option value="x3">b</option></select>',
|
||||
'<select class="shiny-input-select form-control" id="id"><option value="x1" selected>a</option>\n<option value="x2">a</option>\n<option value="x3">b</option></select>',
|
||||
format(x)
|
||||
))
|
||||
|
||||
@@ -249,7 +249,7 @@ test_that("selectInput selects items by default", {
|
||||
|
||||
# Nothing selected when choices=NULL
|
||||
expect_true(grepl(fixed = TRUE,
|
||||
'<select id="x" class="form-control"></select>',
|
||||
'<select class="shiny-input-select form-control" id="x"></select>',
|
||||
format(selectInput('x', NULL, NULL, selectize = FALSE))
|
||||
))
|
||||
|
||||
|
||||
@@ -268,3 +268,27 @@ test_that("quoToFunction handles nested quosures", {
|
||||
func <- quoToFunction(quo_outer, "foo")
|
||||
expect_identical(func(), 2)
|
||||
})
|
||||
|
||||
|
||||
|
||||
test_that("toJSON can set digits using options - default", {
|
||||
withr::local_options(list(shiny.json.digits = NULL))
|
||||
expect_equal(
|
||||
as.character(toJSON(pi)),
|
||||
"[3.141592653589793]"
|
||||
)
|
||||
})
|
||||
test_that("toJSON can set digits using options - number", {
|
||||
withr::local_options(list(shiny.json.digits = 4))
|
||||
expect_equal(
|
||||
as.character(toJSON(pi)),
|
||||
"[3.1416]"
|
||||
)
|
||||
})
|
||||
test_that("toJSON can set digits using options - asis number", {
|
||||
withr::local_options(list(shiny.json.digits = I(4)))
|
||||
expect_equal(
|
||||
as.character(toJSON(pi)),
|
||||
"[3.142]"
|
||||
)
|
||||
})
|
||||
|
||||
@@ -3,8 +3,9 @@ new file mode 100644
|
||||
index 00000000..ba052f8b
|
||||
--- /dev/null
|
||||
+++ b/inst/www/shared/ionrangeslider/scss/shiny.scss
|
||||
@@ -0,0 +1,173 @@
|
||||
@@ -0,0 +1,201 @@
|
||||
+/* 'shiny' skin for Ion.RangeSlider, largely based on the 'big' skin, but with smaller dimensions, grayscale grid text, and without gradients
|
||||
+© Posit, PBC, 2023
|
||||
+© RStudio, Inc, 2014
|
||||
+© Denis Ineshin, 2014 https://github.com/IonDen
|
||||
+© guybowden, 2014 https://github.com/guybowden
|
||||
@@ -85,6 +86,19 @@ index 00000000..ba052f8b
|
||||
+ background-color: $line_bg_color;
|
||||
+ border: $line_border;
|
||||
+ @include border-radius-shim($line_height);
|
||||
+
|
||||
+ // Increase the touch target area of the slider line
|
||||
+ overflow: visible;
|
||||
+ &::before {
|
||||
+ content: "";
|
||||
+ display: block;
|
||||
+ position: relative;
|
||||
+ cursor: s-resize; // downward arrow
|
||||
+ width: 100%;
|
||||
+ height: $handle_height;
|
||||
+ top: -(($handle_height - $line_height / 2) / 2);
|
||||
+ z-index: 1; // raise touch area above grid
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ .#{$name}-bar {
|
||||
@@ -93,10 +107,23 @@ index 00000000..ba052f8b
|
||||
+ border-top: 1px solid $bar_color;
|
||||
+ border-bottom: 1px solid $bar_color;
|
||||
+ background: $bar_color;
|
||||
+ cursor: s-resize; // downard arrow, overwritten when a range
|
||||
+ z-index: 2;
|
||||
+
|
||||
+ &--single {
|
||||
+ @include border-radius-shim($line_height 0 0 $line_height);
|
||||
+ }
|
||||
+
|
||||
+ // Increase the touch target area of the slider bar
|
||||
+ &::before {
|
||||
+ content: "";
|
||||
+ display: block;
|
||||
+ position: relative;
|
||||
+ width: 100%;
|
||||
+ height: $handle_height;
|
||||
+ top: -(($handle_height - $line_height / 2) / 2);
|
||||
+ z-index: 2; // raise touch area above line touch target
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // sliderInput() doesn't currently support from_min/from_max, so this isn't relevant
|
||||
@@ -120,6 +147,7 @@ index 00000000..ba052f8b
|
||||
+ background-color: $handle_color;
|
||||
+ box-shadow: $handle_box_shadow;
|
||||
+ border-radius: $handle_width;
|
||||
+ z-index: 2;
|
||||
+
|
||||
+ &.state_hover,
|
||||
+ &:hover {
|
||||
|
||||
Reference in New Issue
Block a user