Compare commits

..

2 Commits

Author SHA1 Message Date
gadenbuie
bbca8071f4 yarn build (GitHub Actions) 2024-04-30 15:34:29 +00:00
Garrick Aden-Buie
090872f4f2 fix: make remove modal and notification also async 2024-04-30 11:20:43 -04:00
109 changed files with 9501 additions and 11284 deletions

1
.github/.gitignore vendored
View File

@@ -1 +0,0 @@
*.html

View File

@@ -5,7 +5,6 @@ echo "Updating package.json version to match DESCRIPTION Version"
Rscript ./tools/updatePackageJsonVersion.R
if [ -n "$(git status --porcelain package.json)" ]
then
echo "package.json has changed after running ./tools/updatePackageJsonVersion.R. Re-running 'yarn build'"
yarn build
git add ./inst package.json && git commit -m 'Sync package version (GitHub Actions)' || echo "No package version to commit"
else

View File

@@ -1,19 +0,0 @@
# Workflow derived from https://github.com/r-wasm/actions/tree/v1/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
release:
# Must republish release to update assets
types: [ published ]
name: Build and deploy wasm R package image
jobs:
release-file-system-image:
uses: r-wasm/actions/.github/workflows/release-file-system-image.yml@v1
permissions:
# For publishing artifact files to the release
contents: write
# To download GitHub Packages within action
repository-projects: read
with:
strip: "demo, doc, examples, help, html, include, tests, vignette"

View File

@@ -15,10 +15,4 @@
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
},
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
},
}

View File

@@ -1,7 +1,7 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.8.1.9991
Version: 1.8.1.9000
Authors@R: c(
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"),
@@ -128,8 +128,6 @@ Collate:
'map.R'
'utils.R'
'bootstrap.R'
'busy-indicators-spinners.R'
'busy-indicators.R'
'cache-utils.R'
'deprecated.R'
'devmode.R'
@@ -213,36 +211,3 @@ RdMacros: lifecycle
Config/testthat/edition: 3
Config/Needs/check:
shinytest2
Config/Needs/wasm:
R6,
Rcpp,
base64enc,
bslib,
cachem,
cli,
codetools,
commonmark,
crayon,
digest,
ellipsis,
fastmap,
fontawesome,
fs,
glue,
htmltools,
httpuv,
jquerylib,
jsonlite,
later,
lifecycle,
magrittr,
memoise,
mime,
promises,
rappdirs,
renv,
rlang,
sass,
sourcetools,
withr,
xtable

View File

@@ -78,7 +78,6 @@ export(br)
export(browserViewer)
export(brushOpts)
export(brushedPoints)
export(busyIndicatorOptions)
export(callModule)
export(captureStackTraces)
export(checkboxGroupInput)
@@ -318,7 +317,6 @@ export(updateTextInput)
export(updateVarSelectInput)
export(updateVarSelectizeInput)
export(urlModal)
export(useBusyIndicators)
export(validate)
export(validateCssUnit)
export(varSelectInput)

View File

@@ -1,14 +1,7 @@
# shiny (development version)
## New features and improvements
* Added new functions, `useBusyIndicators()` and `busyIndicatorOptions()`, for enabling and customizing busy indication. Busy indicators provide a visual cue to users when the server is busy calculating outputs or otherwise serving requests to the client. When enabled, a spinner is shown on each calculating/recalculating output, and a pulsing banner is shown at the top of the page when the app is otherwise busy. (#4040)
* Output bindings now include the `.recalculating` CSS class when they are first bound, up until the first render. This makes it possible/easier to show progress indication when the output is calculating for the first time. (#4039)
## Bug fixes
* `downloadButton()` and `downloadLink()` are now disabled up until they are fully initialized. This prevents the user from clicking the button/link before the download is ready. (#4041)
* Output bindings that are removed, invalidated, then inserted again (while invalidated) now correctly include the `.recalculating` CSS class. (#4039)
* Fixed a recent issue with `uiOutput()` and `conditionalPanel()` not properly lower opacity when recalculation (in a Bootstrap 5 context). (#4027)
# shiny 1.8.1.1

View File

@@ -1276,13 +1276,10 @@ downloadButton <- function(outputId,
...,
icon = shiny::icon("download")) {
tags$a(id=outputId,
class='btn btn-default shiny-download-link disabled',
class=class,
class=paste('btn btn-default shiny-download-link', class),
href='',
target='_blank',
download=NA,
"aria-disabled"="true",
tabindex="-1",
validateIcon(icon),
label, ...)
}
@@ -1291,13 +1288,10 @@ downloadButton <- function(outputId,
#' @export
downloadLink <- function(outputId, label="Download", class=NULL, ...) {
tags$a(id=outputId,
class='shiny-download-link disabled',
class=class,
class=paste(c('shiny-download-link', class), collapse=" "),
href='',
target='_blank',
download=NA,
"aria-disabled"="true",
tabindex="-1",
label, ...)
}

View File

@@ -1,4 +0,0 @@
# Generated by tools/updateSpinnerTypes.R: do not edit by hand
.busySpinnerTypes <-
c("ring", "ring2", "ring3", "bars", "bars2", "bars3", "pulse",
"pulse2", "pulse3", "dots", "dots2", "dots3")

View File

@@ -1,249 +0,0 @@
#' Enable/disable busy indication
#'
#' Busy indicators provide a visual cue to users when the server is busy
#' calculating outputs or otherwise performing tasks (e.g., producing
#' downloads). When enabled, a spinner is shown on each
#' calculating/recalculating output, and a pulsing banner is shown at the top of
#' the page when the app is otherwise busy. Busy indication is enabled by
#' default for UI created with \pkg{bslib}, but must be enabled otherwise. To
#' enable/disable, include the result of this function in anywhere in the app's
#' UI.
#'
#' When both `spinners` and `pulse` are set to `TRUE`, the pulse is
#' automatically disabled when spinner(s) are active. When both `spinners` and
#' `pulse` are set to `FALSE`, no busy indication is shown (other than the
#' graying out of recalculating outputs).
#'
#' @param ... Currently ignored.
#' @param spinners Whether to show a spinner on each calculating/recalculating
#' output.
#' @param pulse Whether to show a pulsing banner at the top of the page when the
#' app is busy.
#'
#' @export
#' @seealso [busyIndicatorOptions()] for customizing the appearance of the busy
#' indicators.
#' @examplesIf rlang::is_interactive()
#'
#' library(bslib)
#'
#' ui <- page_fillable(
#' useBusyIndicators(),
#' card(
#' card_header(
#' "A plot",
#' input_task_button("simulate", "Simulate"),
#' class = "d-flex justify-content-between align-items-center"
#' ),
#' plotOutput("p"),
#' )
#' )
#'
#' server <- function(input, output) {
#' output$p <- renderPlot({
#' input$simulate
#' Sys.sleep(4)
#' plot(x = rnorm(100), y = rnorm(100))
#' })
#' }
#'
#' shinyApp(ui, server)
useBusyIndicators <- function(..., spinners = TRUE, pulse = TRUE) {
rlang::check_dots_empty()
attrs <- list("shinyBusySpinners" = spinners, "shinyBusyPulse" = pulse)
js <- vapply(names(attrs), character(1), FUN = function(key) {
if (attrs[[key]]) {
sprintf("document.documentElement.dataset.%s = 'true';", key)
} else {
sprintf("delete document.documentElement.dataset.%s;", key)
}
})
js <- HTML(paste(js, collapse = "\n"))
# TODO: it'd be nice if htmltools had something like a page_attrs() that allowed us
# to do this without needing to inject JS into the head.
tags$script(js)
}
#' Customize busy indicator options
#'
#' When busy indicators are enabled (see [useBusyIndicators()]), a spinner is
#' shown on each calculating/recalculating output, and a pulsing banner is shown
#' at the top of the page when the app is otherwise busy. This function allows
#' you to customize the appearance of those busy indicators. To apply the
#' customization, include the result of this function inside the app's UI.
#'
#' @param ... Currently ignored.
#' @param spinner_type The type of spinner. Pre-bundled types include:
#' '`r paste0(.busySpinnerTypes, collapse = "', '")`'.
#'
#' A path to a local SVG file can also be provided. The SVG should adhere to
#' the following rules:
#' * The SVG itself should contain the animation.
#' * It should avoid absolute sizes (the spinner's containing DOM element
#' size is set in CSS by `spinner_size`, so it should fill that container).
#' * It should avoid setting absolute colors (the spinner's containing DOM element
#' color is set in CSS by `spinner_color`, so it should inherit that color).
#' @param spinner_color The color of the spinner. This can be any valid CSS
#' color. Defaults to the app's "primary" color if Bootstrap is on the page.
#' @param spinner_size The size of the spinner. This can be any valid CSS size.
#' @param spinner_delay The amount of time to wait before showing the spinner.
#' This can be any valid CSS time and can be useful for not showing the spinner
#' if the computation finishes quickly.
#' @param spinner_selector A character string containing a CSS selector for
#' scoping the spinner customization. The default (`NULL`) will apply the
#' spinner customization to the parent element of the spinner.
#' @param pulse_background A CSS background definition for the pulse. The
#' default uses a
#' [linear-gradient](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient)
#' of the theme's indigo, purple, and pink colors.
#' @param pulse_height The height of the pulsing banner. This can be any valid
#' CSS size.
#' @param pulse_speed The speed of the pulsing banner. This can be any valid CSS
#' time.
#'
#' @export
#' @seealso [useBusyIndicators()] for enabling/disabling busy indicators.
#' @examplesIf rlang::is_interactive()
#'
#' library(bslib)
#'
#' card_ui <- function(id, spinner_type = id) {
#' card(
#' busyIndicatorOptions(spinner_type = spinner_type),
#' card_header(paste("Spinner:", spinner_type)),
#' plotOutput(shiny::NS(id, "plot"))
#' )
#' }
#'
#' card_server <- function(id, simulate = reactive()) {
#' moduleServer(
#' id = id,
#' function(input, output, session) {
#' output$plot <- renderPlot({
#' Sys.sleep(1)
#' simulate()
#' plot(x = rnorm(100), y = rnorm(100))
#' })
#' }
#' )
#' }
#'
#' ui <- page_fillable(
#' useBusyIndicators(),
#' input_task_button("simulate", "Simulate", icon = icon("refresh")),
#' layout_columns(
#' card_ui("ring"),
#' card_ui("bars"),
#' card_ui("dots"),
#' card_ui("pulse"),
#' col_widths = 6
#' )
#' )
#'
#' server <- function(input, output, session) {
#' simulate <- reactive(input$simulate)
#' card_server("ring", simulate)
#' card_server("bars", simulate)
#' card_server("dots", simulate)
#' card_server("pulse", simulate)
#' }
#'
#' shinyApp(ui, server)
#'
busyIndicatorOptions <- function(
...,
spinner_type = NULL,
spinner_color = NULL,
spinner_size = NULL,
spinner_delay = NULL,
spinner_selector = NULL,
pulse_background = NULL,
pulse_height = NULL,
pulse_speed = NULL
) {
rlang::check_dots_empty()
res <- tagList(
spinnerOptions(
type = spinner_type,
color = spinner_color,
size = spinner_size,
delay = spinner_delay,
selector = spinner_selector
),
pulseOptions(
background = pulse_background,
height = pulse_height,
speed = pulse_speed
)
)
bslib::as.card_item(dropNulls(res))
}
spinnerOptions <- function(type = NULL, color = NULL, size = NULL, delay = NULL, selector = NULL) {
if (is.null(type) && is.null(color) && is.null(size) && is.null(delay) && is.null(selector)) {
return(NULL)
}
url <- NULL
if (!is.null(type)) {
stopifnot(is.character(type) && length(type) == 1)
if (file.exists(type) && grepl("\\.svg$", type)) {
typeRaw <- readBin(type, "raw", n = file.info(type)$size)
url <- sprintf("url('data:image/svg+xml;base64,%s')", rawToBase64(typeRaw))
} else {
type <- rlang::arg_match(type, .busySpinnerTypes)
url <- sprintf("url('spinners/%s.svg')", type)
}
}
# Options controlled via CSS variables.
css_vars <- htmltools::css(
"--shiny-spinner-url" = url,
"--shiny-spinner-color" = htmltools::parseCssColors(color),
"--shiny-spinner-size" = htmltools::validateCssUnit(size),
"--shiny-spinner-delay" = delay
)
id <- NULL
if (is.null(selector)) {
id <- paste0("spinner-options-", p_randomInt(100, 1000000))
selector <- sprintf(":has(> #%s)", id)
}
css <- HTML(paste0(selector, " {", css_vars, "}"))
tags$style(css, id = id)
}
pulseOptions <- function(background = NULL, height = NULL, speed = NULL) {
if (is.null(background) && is.null(height) && is.null(speed)) {
return(NULL)
}
css_vars <- htmltools::css(
"--shiny-pulse-background" = background,
"--shiny-pulse-height" = htmltools::validateCssUnit(height),
"--shiny-pulse-speed" = speed
)
tags$style(HTML(paste0(":root {", css_vars, "}")))
}
busyIndicatorDependency <- function() {
htmlDependency(
name = "shiny-busy-indicators",
version = get_package_version("shiny"),
src = "www/shared/busy-indicators",
package = "shiny",
stylesheet = "busy-indicators.css"
)
}

View File

@@ -114,7 +114,6 @@ jqueryDependency <- function() {
shinyDependencies <- function() {
list(
bslib::bs_dependency_defer(shinyDependencyCSS),
busyIndicatorDependency(),
htmlDependency(
name = "shiny-javascript",
version = get_package_version("shiny"),

View File

@@ -1515,44 +1515,41 @@ hybrid_chain <- function(expr, ..., catch = NULL, finally = NULL,
do <- function() {
runFinally <- TRUE
on.exit({ if (runFinally && !is.null(finally)) finally() })
catch_e <- NULL
delayedAssign("do_catch",
if (!is.null(catch)) {
catch(catch_e)
return()
} else {
stop(catch_e)
}
)
handlers <- list(error = function(e) { catch_e <<- e; do_catch })
classes <- names(handlers)
.Internal(.addCondHands(classes, handlers, parent.frame(), NULL, TRUE))
result <- withVisible(force(expr))
if (promises::is.promising(result$value)) {
# Purposefully NOT including domain (nor replace), as we're already in
# the domain at this point
p <- promise_chain(valueWithVisible(result), ..., catch = catch, finally = finally)
runFinally <- FALSE
p
} else {
result <- Reduce(
function(v, func) {
if (v$visible) {
withVisible(func(v$value))
tryCatch(
{
captureStackTraces({
result <- withVisible(force(expr))
if (promises::is.promising(result$value)) {
# Purposefully NOT including domain (nor replace), as we're already in
# the domain at this point
p <- promise_chain(valueWithVisible(result), ..., catch = catch, finally = finally)
runFinally <- FALSE
p
} else {
withVisible(func(invisible(v$value)))
}
},
list(...),
result
)
result <- Reduce(
function(v, func) {
if (v$visible) {
withVisible(func(v$value))
} else {
withVisible(func(invisible(v$value)))
}
},
list(...),
result
)
valueWithVisible(result)
}
valueWithVisible(result)
}
})
},
error = function(e) {
if (!is.null(catch))
catch(e)
else
stop(e)
},
finally = if (runFinally && !is.null(finally)) finally()
)
}
if (!is.null(domain)) {

View File

@@ -1,154 +0,0 @@
<mxfile host="app.diagrams.net" modified="2024-05-07T22:40:15.581Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" etag="Zsitjb4PT-sW3A63SWd7" version="24.3.1" type="device">
<diagram name="Page-1" id="zz6aoPEyabkTD7ESu8ts">
<mxGraphModel dx="595" dy="889" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-1" value="Initial" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="120" y="270" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-2" value="Running" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="270" y="270" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-3" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-1" target="DS1AFzV_2DL1v2c9v1jZ-2" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="260" y="480" as="sourcePoint" />
<mxPoint x="310" y="270" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-4" value="Recalculating" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="210" y="250" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-6" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-2" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="220" as="sourcePoint" />
<mxPoint x="310" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-7" value="Idle" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="270" y="350" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-8" value="Recalculated" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="330" y="310" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-9" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-7" target="DS1AFzV_2DL1v2c9v1jZ-10" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="320" as="sourcePoint" />
<mxPoint x="310" y="440" as="targetPoint" />
<Array as="points">
<mxPoint x="320" y="410" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-10" value="Value" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="280" y="440" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-11" value="Error" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="370" y="440" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-12" value="Persistent" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="90" y="440" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-13" value="Cancel" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="180" y="440" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-14" value="&lt;span style=&quot;text-align: start; font-size: 10pt; font-family: Arial;&quot; data-sheets-userformat=&quot;{&amp;quot;2&amp;quot;:513,&amp;quot;3&amp;quot;:{&amp;quot;1&amp;quot;:0},&amp;quot;12&amp;quot;:0}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;{progress: {type: \&amp;quot;binding\&amp;quot;, message: {persistent: true}}}&amp;quot;}&quot; data-sheets-root=&quot;1&quot;&gt;{progress: {type: &quot;binding&quot;, message: {persistent: true}}}&lt;/span&gt;" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="45" y="340" width="170" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-15" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-10" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="400" as="sourcePoint" />
<mxPoint x="310" y="550" as="targetPoint" />
<Array as="points">
<mxPoint x="320" y="520" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-16" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-11" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="490" as="sourcePoint" />
<mxPoint x="320" y="550" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-17" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-12" target="DS1AFzV_2DL1v2c9v1jZ-18" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="330" y="500" as="sourcePoint" />
<mxPoint x="290" y="540" as="targetPoint" />
<Array as="points" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-18" value="Invalidated" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="260" y="550" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-20" value="" style="curved=1;endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-18" target="DS1AFzV_2DL1v2c9v1jZ-2" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="260" y="480" as="sourcePoint" />
<mxPoint x="310" y="430" as="targetPoint" />
<Array as="points">
<mxPoint x="420" y="610" />
<mxPoint x="550" y="470" />
<mxPoint x="440" y="320" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-23" value="Recalculating" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="450" y="340" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-24" value="" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-2" target="DS1AFzV_2DL1v2c9v1jZ-12" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="400" as="sourcePoint" />
<mxPoint x="320" y="450" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-25" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0.395;entryY=-0.025;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-7" target="DS1AFzV_2DL1v2c9v1jZ-11" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="330" y="410" as="sourcePoint" />
<mxPoint x="330" y="460" as="targetPoint" />
<Array as="points">
<mxPoint x="380" y="410" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-26" value="" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-7" target="DS1AFzV_2DL1v2c9v1jZ-13" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="340" y="420" as="sourcePoint" />
<mxPoint x="340" y="470" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-27" value="Value" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="270" y="400" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-28" value="Error" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="330" y="400" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-29" value="No message" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="200" y="400" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-30" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-13" target="DS1AFzV_2DL1v2c9v1jZ-18" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="230" y="490" as="sourcePoint" />
<mxPoint x="300" y="558" as="targetPoint" />
<Array as="points">
<mxPoint x="240" y="520" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-31" value="&lt;span style=&quot;font-family: Arial; font-size: 13px; text-align: left; white-space: pre-wrap; background-color: rgb(255, 255, 255);&quot;&gt;{progress: {type: &quot;binding&quot;}}&lt;/span&gt;" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="190" y="490" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="DS1AFzV_2DL1v2c9v1jZ-35" value="&lt;h1 style=&quot;margin-top: 0px;&quot;&gt;Shiny output progress states&lt;/h1&gt;&lt;p&gt;This diagram depicts a state machine of output binding progress state. Each node represents a possible state and each edge represents a server-&amp;gt;client message that moves outputs from one state to another. &lt;b&gt;If a node is highlighted in blue&lt;/b&gt;, then the output should be showing a busy state when visible (i.e., &lt;font face=&quot;Courier New&quot;&gt;binding.showProgress(true)&lt;/font&gt;)&lt;/p&gt;" style="text;html=1;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
<mxGeometry x="85" y="120" width="465" height="120" as="geometry" />
</mxCell>
<mxCell id="J9lKobNiy15ndT9nfcn--1" value="" style="curved=1;endArrow=classic;html=1;rounded=0;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="DS1AFzV_2DL1v2c9v1jZ-7" target="DS1AFzV_2DL1v2c9v1jZ-18">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="280" y="480" as="sourcePoint" />
<mxPoint x="220" y="510" as="targetPoint" />
<Array as="points">
<mxPoint x="610" y="420" />
</Array>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 312 KiB

View File

@@ -1,2 +0,0 @@
/*! shiny 1.8.1.9001 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
:where([data-shiny-busy-spinners] .recalculating){position:relative}[data-shiny-busy-spinners] .recalculating{opacity:1}[data-shiny-busy-spinners] .recalculating:after{position:absolute;content:"";--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));--_shiny-spinner-size: var(--shiny-spinner-size, 32px);--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);background:var(--_shiny-spinner-color);width:var(--_shiny-spinner-size);height:var(--_shiny-spinner-size);inset:calc(50% - var(--_shiny-spinner-size) / 2);mask-image:var(--_shiny-spinner-url);-webkit-mask-image:var(--_shiny-spinner-url);opacity:0;animation-delay:var(--_shiny-spinner-delay);animation-name:fade-in;animation-duration:.25s}[data-shiny-busy-spinners] .recalculating>*:not(.recalculating){opacity:.2;transition:opacity .25s ease var(--shiny-spinner-delay, 1s)}[data-shiny-busy-spinners] .recalculating.shiny-html-output:after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, var(--bs-body-bg, #fff), var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), var(--bs-body-bg, #fff) ) );--_shiny-pulse-height: var(--shiny-pulse-height, 5px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.85s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(.recalculating):after{display:none}[data-shiny-busy-spinners][data-shiny-busy-pulse].shiny-busy:has(#shiny-disconnected-overlay):after{display:none}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:after{--_shiny-pulse-background: var( --shiny-pulse-background, linear-gradient( 120deg, var(--bs-body-bg, #fff), var(--bs-indigo, #4b00c1), var(--bs-purple, #74149c), var(--bs-pink, #bf007f), var(--bs-body-bg, #fff) ) );--_shiny-pulse-height: var(--shiny-pulse-height, 5px);--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.85s);position:fixed;top:0;left:0;height:var(--_shiny-pulse-height);background:var(--_shiny-pulse-background);z-index:9999;animation-name:busy-page-pulse;animation-duration:var(--_shiny-pulse-speed);animation-iteration-count:infinite;animation-timing-function:ease-in-out;content:""}[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]).shiny-busy:has(#shiny-disconnected-overlay):after{display:none}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes busy-page-pulse{0%{left:-75%;width:75%}50%{left:100%;width:75%}to{left:-75%;width:75%}}

View File

@@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) Utkarsh Verma
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_hzlK{animation:spinner_vc4H .8s linear infinite;animation-delay:-.8s}.spinner_koGT{animation-delay:-.65s}.spinner_YF1u{animation-delay:-.5s}@keyframes spinner_vc4H{0%{y:1px;height:22px}93.75%{y:5px;height:14px;opacity:.2}}</style><rect class="spinner_hzlK" x="1" y="1" width="6" height="22"/><rect class="spinner_hzlK spinner_koGT" x="9" y="1" width="6" height="22"/><rect class="spinner_hzlK spinner_YF1u" x="17" y="1" width="6" height="22"/></svg>

Before

Width:  |  Height:  |  Size: 526 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_jCIR{animation:spinner_B8Vq .9s linear infinite;animation-delay:-.9s}.spinner_upm8{animation-delay:-.8s}.spinner_2eL5{animation-delay:-.7s}.spinner_Rp9l{animation-delay:-.6s}.spinner_dy3W{animation-delay:-.5s}@keyframes spinner_B8Vq{0%,66.66%{animation-timing-function:cubic-bezier(0.36,.61,.3,.98);y:6px;height:12px}33.33%{animation-timing-function:cubic-bezier(0.36,.61,.3,.98);y:1px;height:22px}}</style><rect class="spinner_jCIR" x="1" y="6" width="2.8" height="12"/><rect class="spinner_jCIR spinner_upm8" x="5.8" y="6" width="2.8" height="12"/><rect class="spinner_jCIR spinner_2eL5" x="10.6" y="6" width="2.8" height="12"/><rect class="spinner_jCIR spinner_Rp9l" x="15.4" y="6" width="2.8" height="12"/><rect class="spinner_jCIR spinner_dy3W" x="20.2" y="6" width="2.8" height="12"/></svg>

Before

Width:  |  Height:  |  Size: 873 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_OSmW{transform-origin:center;animation:spinner_T6mA .75s step-end infinite}@keyframes spinner_T6mA{8.3%{transform:rotate(30deg)}16.6%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.3%{transform:rotate(120deg)}41.6%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.3%{transform:rotate(210deg)}66.6%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.3%{transform:rotate(300deg)}91.6%{transform:rotate(330deg)}100%{transform:rotate(360deg)}}</style><g class="spinner_OSmW"><rect x="11" y="1" width="2" height="5" opacity=".14"/><rect x="11" y="1" width="2" height="5" transform="rotate(30 12 12)" opacity=".29"/><rect x="11" y="1" width="2" height="5" transform="rotate(60 12 12)" opacity=".43"/><rect x="11" y="1" width="2" height="5" transform="rotate(90 12 12)" opacity=".57"/><rect x="11" y="1" width="2" height="5" transform="rotate(120 12 12)" opacity=".71"/><rect x="11" y="1" width="2" height="5" transform="rotate(150 12 12)" opacity=".86"/><rect x="11" y="1" width="2" height="5" transform="rotate(180 12 12)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_b2T7{animation:spinner_xe7Q .8s linear infinite}.spinner_YRVV{animation-delay:-.65s}.spinner_c9oY{animation-delay:-.5s}@keyframes spinner_xe7Q{93.75%,100%{r:3px}46.875%{r:.2px}}</style><circle class="spinner_b2T7" cx="4" cy="12" r="3"/><circle class="spinner_b2T7 spinner_YRVV" cx="12" cy="12" r="3"/><circle class="spinner_b2T7 spinner_c9oY" cx="20" cy="12" r="3"/></svg>

Before

Width:  |  Height:  |  Size: 449 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_Wezc{transform-origin:center;animation:spinner_Oiah .75s step-end infinite}@keyframes spinner_Oiah{8.3%{transform:rotate(30deg)}16.6%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.3%{transform:rotate(120deg)}41.6%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.3%{transform:rotate(210deg)}66.6%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.3%{transform:rotate(300deg)}91.6%{transform:rotate(330deg)}100%{transform:rotate(360deg)}}</style><g class="spinner_Wezc"><circle cx="12" cy="2.5" r="1.5" opacity=".14"/><circle cx="16.75" cy="3.77" r="1.5" opacity=".29"/><circle cx="20.23" cy="7.25" r="1.5" opacity=".43"/><circle cx="21.50" cy="12.00" r="1.5" opacity=".57"/><circle cx="20.23" cy="16.75" r="1.5" opacity=".71"/><circle cx="16.75" cy="20.23" r="1.5" opacity=".86"/><circle cx="12" cy="21.5" r="1.5"/></g></svg>

Before

Width:  |  Height:  |  Size: 926 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_DupU{animation:spinner_sM3D 1.2s infinite}.spinner_GWtZ{animation-delay:.1s}.spinner_dwN6{animation-delay:.2s}.spinner_46QP{animation-delay:.3s}.spinner_PD82{animation-delay:.4s}.spinner_eUgh{animation-delay:.5s}.spinner_eUaP{animation-delay:.6s}.spinner_j38H{animation-delay:.7s}.spinner_tVmX{animation-delay:.8s}.spinner_DQhX{animation-delay:.9s}.spinner_GIL4{animation-delay:1s}.spinner_n0Yb{animation-delay:1.1s}@keyframes spinner_sM3D{0%,50%{animation-timing-function:cubic-bezier(0,1,0,1);r:0}10%{animation-timing-function:cubic-bezier(.53,0,.61,.73);r:2px}}</style><circle class="spinner_DupU" cx="12" cy="3" r="0"/><circle class="spinner_DupU spinner_GWtZ" cx="16.50" cy="4.21" r="0"/><circle class="spinner_DupU spinner_n0Yb" cx="7.50" cy="4.21" r="0"/><circle class="spinner_DupU spinner_dwN6" cx="19.79" cy="7.50" r="0"/><circle class="spinner_DupU spinner_GIL4" cx="4.21" cy="7.50" r="0"/><circle class="spinner_DupU spinner_46QP" cx="21.00" cy="12.00" r="0"/><circle class="spinner_DupU spinner_DQhX" cx="3.00" cy="12.00" r="0"/><circle class="spinner_DupU spinner_PD82" cx="19.79" cy="16.50" r="0"/><circle class="spinner_DupU spinner_tVmX" cx="4.21" cy="16.50" r="0"/><circle class="spinner_DupU spinner_eUgh" cx="16.50" cy="19.79" r="0"/><circle class="spinner_DupU spinner_j38H" cx="7.50" cy="19.79" r="0"/><circle class="spinner_DupU spinner_eUaP" cx="12" cy="21" r="0"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_ZCsl{animation:spinner_qV4G 1.2s cubic-bezier(0.52,.6,.25,.99) infinite}.spinner_gaIW{animation-delay:.6s}@keyframes spinner_qV4G{0%{r:0;opacity:1}100%{r:11px;opacity:0}}</style><circle class="spinner_ZCsl" cx="12" cy="12" r="0"/><circle class="spinner_ZCsl spinner_gaIW" cx="12" cy="12" r="0"/></svg>

Before

Width:  |  Height:  |  Size: 378 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_ngNb{animation:spinner_ZRWK 1.2s cubic-bezier(0.52,.6,.25,.99) infinite}.spinner_6TBP{animation-delay:.6s}@keyframes spinner_ZRWK{0%{transform:translate(12px,12px) scale(0);opacity:1}100%{transform:translate(0,0) scale(1);opacity:0}}</style><path class="spinner_ngNb" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)"/><path class="spinner_ngNb spinner_6TBP" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)"/></svg>

Before

Width:  |  Height:  |  Size: 635 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_Uvk8{animation:spinner_otJF 1.6s cubic-bezier(.52,.6,.25,.99) infinite}.spinner_ypeD{animation-delay:.2s}.spinner_y0Rj{animation-delay:.4s}@keyframes spinner_otJF{0%{transform:translate(12px,12px) scale(0);opacity:1}75%,100%{transform:translate(0,0) scale(1);opacity:0}}</style><path class="spinner_Uvk8" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)"/><path class="spinner_Uvk8 spinner_ypeD" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)"/><path class="spinner_Uvk8 spinner_y0Rj" d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)"/></svg>

Before

Width:  |  Height:  |  Size: 834 B

View File

@@ -1 +0,0 @@
<svg stroke="#000" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_V8m1{transform-origin:center;animation:spinner_zKoa 2s linear infinite}.spinner_V8m1 circle{stroke-linecap:round;animation:spinner_YpZS 1.5s ease-in-out infinite}@keyframes spinner_zKoa{100%{transform:rotate(360deg)}}@keyframes spinner_YpZS{0%{stroke-dasharray:0 150;stroke-dashoffset:0}47.5%{stroke-dasharray:42 150;stroke-dashoffset:-16}95%,100%{stroke-dasharray:42 150;stroke-dashoffset:-59}}</style><g class="spinner_V8m1"><circle cx="12" cy="12" r="9.5" fill="none" stroke-width="3"></circle></g></svg>

Before

Width:  |  Height:  |  Size: 598 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_ajPY{transform-origin:center;animation:spinner_AtaB .75s infinite linear}@keyframes spinner_AtaB{100%{transform:rotate(360deg)}}</style><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z" class="spinner_ajPY"/></svg>

Before

Width:  |  Height:  |  Size: 509 B

View File

@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_aj0A{transform-origin:center;animation:spinner_KYSC .75s infinite linear}@keyframes spinner_KYSC{100%{transform:rotate(360deg)}}</style><path d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" class="spinner_aj0A"/></svg>

Before

Width:  |  Height:  |  Size: 412 B

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/*! shiny 1.8.1.9001 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
/*! shiny 1.8.1.9000 | (c) 2012-2024 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

View File

@@ -1,3 +1,3 @@
/*! shiny 1.8.1.9001 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
/*! shiny 1.8.1.9000 | (c) 2012-2024 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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,117 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/busy-indicators.R
\name{busyIndicatorOptions}
\alias{busyIndicatorOptions}
\title{Customize busy indicator options}
\usage{
busyIndicatorOptions(
...,
spinner_type = NULL,
spinner_color = NULL,
spinner_size = NULL,
spinner_delay = NULL,
spinner_selector = NULL,
pulse_background = NULL,
pulse_height = NULL,
pulse_speed = NULL
)
}
\arguments{
\item{...}{Currently ignored.}
\item{spinner_type}{The type of spinner. Pre-bundled types include:
'ring', 'ring2', 'ring3', 'bars', 'bars2', 'bars3', 'pulse', 'pulse2', 'pulse3', 'dots', 'dots2', 'dots3'.
A path to a local SVG file can also be provided. The SVG should adhere to
the following rules:
\itemize{
\item The SVG itself should contain the animation.
\item It should avoid absolute sizes (the spinner's containing DOM element
size is set in CSS by \code{spinner_size}, so it should fill that container).
\item It should avoid setting absolute colors (the spinner's containing DOM element
color is set in CSS by \code{spinner_color}, so it should inherit that color).
}}
\item{spinner_color}{The color of the spinner. This can be any valid CSS
color. Defaults to the app's "primary" color if Bootstrap is on the page.}
\item{spinner_size}{The size of the spinner. This can be any valid CSS size.}
\item{spinner_delay}{The amount of time to wait before showing the spinner.
This can be any valid CSS time and can be useful for not showing the spinner
if the computation finishes quickly.}
\item{spinner_selector}{A character string containing a CSS selector for
scoping the spinner customization. The default (\code{NULL}) will apply the
spinner customization to the parent element of the spinner.}
\item{pulse_background}{A CSS background definition for the pulse. The
default uses a
\href{https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient}{linear-gradient}
of the theme's indigo, purple, and pink colors.}
\item{pulse_height}{The height of the pulsing banner. This can be any valid
CSS size.}
\item{pulse_speed}{The speed of the pulsing banner. This can be any valid CSS
time.}
}
\description{
When busy indicators are enabled (see \code{\link[=useBusyIndicators]{useBusyIndicators()}}), a spinner is
shown on each calculating/recalculating output, and a pulsing banner is shown
at the top of the page when the app is otherwise busy. This function allows
you to customize the appearance of those busy indicators. To apply the
customization, include the result of this function inside the app's UI.
}
\examples{
\dontshow{if (rlang::is_interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
library(bslib)
card_ui <- function(id, spinner_type = id) {
card(
busyIndicatorOptions(spinner_type = spinner_type),
card_header(paste("Spinner:", spinner_type)),
plotOutput(shiny::NS(id, "plot"))
)
}
card_server <- function(id, simulate = reactive()) {
moduleServer(
id = id,
function(input, output, session) {
output$plot <- renderPlot({
Sys.sleep(1)
simulate()
plot(x = rnorm(100), y = rnorm(100))
})
}
)
}
ui <- page_fillable(
useBusyIndicators(),
input_task_button("simulate", "Simulate", icon = icon("refresh")),
layout_columns(
card_ui("ring"),
card_ui("bars"),
card_ui("dots"),
card_ui("pulse"),
col_widths = 6
)
)
server <- function(input, output, session) {
simulate <- reactive(input$simulate)
card_server("ring", simulate)
card_server("bars", simulate)
card_server("dots", simulate)
card_server("pulse", simulate)
}
shinyApp(ui, server)
\dontshow{\}) # examplesIf}
}
\seealso{
\code{\link[=useBusyIndicators]{useBusyIndicators()}} for enabling/disabling busy indicators.
}

View File

@@ -1,65 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/busy-indicators.R
\name{useBusyIndicators}
\alias{useBusyIndicators}
\title{Enable/disable busy indication}
\usage{
useBusyIndicators(..., spinners = TRUE, pulse = TRUE)
}
\arguments{
\item{...}{Currently ignored.}
\item{spinners}{Whether to show a spinner on each calculating/recalculating
output.}
\item{pulse}{Whether to show a pulsing banner at the top of the page when the
app is busy.}
}
\description{
Busy indicators provide a visual cue to users when the server is busy
calculating outputs or otherwise performing tasks (e.g., producing
downloads). When enabled, a spinner is shown on each
calculating/recalculating output, and a pulsing banner is shown at the top of
the page when the app is otherwise busy. Busy indication is enabled by
default for UI created with \pkg{bslib}, but must be enabled otherwise. To
enable/disable, include the result of this function in anywhere in the app's
UI.
}
\details{
When both \code{spinners} and \code{pulse} are set to \code{TRUE}, the pulse is
automatically disabled when spinner(s) are active. When both \code{spinners} and
\code{pulse} are set to \code{FALSE}, no busy indication is shown (other than the
graying out of recalculating outputs).
}
\examples{
\dontshow{if (rlang::is_interactive()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
library(bslib)
ui <- page_fillable(
useBusyIndicators(),
card(
card_header(
"A plot",
input_task_button("simulate", "Simulate"),
class = "d-flex justify-content-between align-items-center"
),
plotOutput("p"),
)
)
server <- function(input, output) {
output$p <- renderPlot({
input$simulate
Sys.sleep(4)
plot(x = rnorm(100), y = rnorm(100))
})
}
shinyApp(ui, server)
\dontshow{\}) # examplesIf}
}
\seealso{
\code{\link[=busyIndicatorOptions]{busyIndicatorOptions()}} for customizing the appearance of the busy
indicators.
}

View File

@@ -3,7 +3,7 @@
"homepage": "https://shiny.rstudio.com",
"repository": "github:rstudio/shiny",
"name": "@types/rstudio-shiny",
"version": "1.8.1-alpha.9001",
"version": "1.8.1-alpha.9000",
"license": "GPL-3.0-only",
"main": "",
"browser": "",
@@ -69,7 +69,6 @@
"phantomjs-prebuilt": "^2.1.16",
"postcss": "^8.3.5",
"prettier": "^2.7.1",
"prettier-plugin-organize-imports": "^3.2.4",
"readcontrol": "^1.0.0",
"replace": "^1.2.1",
"ts-jest": "^26",
@@ -95,11 +94,5 @@
"coverage": "type-coverage -p tsconfig.json --at-least 90",
"circular": "madge --circular --extensions ts srcts/src",
"circular_image": "madge --circular --extensions ts --image madge.svg srcts/src"
},
"prettier": {
"plugins": [
"prettier-plugin-organize-imports"
],
"organizeImportsSkipDestructiveCodeActions": true
}
}

View File

@@ -53,11 +53,3 @@ build({
],
outfile: outDir + "shiny.min.css",
});
build({
...sassOpts,
entryPoints: ["srcts/extras/busy-indicators/busy-indicators.scss"],
outfile: outDir + "busy-indicators/busy-indicators.css",
plugins: [sassPlugin()],
bundle: false,
metafile: true,
});

View File

@@ -1,142 +0,0 @@
:where([data-shiny-busy-spinners] .recalculating) {
position: relative;
}
/* This data atttribute is set by ui.busy_indicators.use() */
[data-shiny-busy-spinners] {
.recalculating {
&::after {
position: absolute;
content: "";
/* ui.busy_indicators.spinner_options() */
--_shiny-spinner-url: var(--shiny-spinner-url, url(spinners/ring.svg));
--_shiny-spinner-color: var(--shiny-spinner-color, var(--bs-primary, #007bc2));
--_shiny-spinner-size: var(--shiny-spinner-size, 32px);
--_shiny-spinner-delay: var(--shiny-spinner-delay, 1s);
background: var(--_shiny-spinner-color);
width: var(--_shiny-spinner-size);
height: var(--_shiny-spinner-size);
inset: calc(50% - var(--_shiny-spinner-size) / 2);
mask-image: var(--_shiny-spinner-url);
-webkit-mask-image: var(--_shiny-spinner-url);
opacity: 0;
animation-delay: var(--_shiny-spinner-delay);
animation-name: fade-in;
animation-duration: 250ms;
}
/*
shiny.css puts `opacity: 0.3` on .recalculating, which unfortunately applies to
the spinner. Undo that, but still apply (smaller) opacity to immediate children
that aren't recalculating.
*/
opacity: 1;
> *:not(.recalculating) {
opacity: 0.2;
transition: opacity 250ms ease var(--shiny-spinner-delay, 1s);
}
/*
Disable spinner on uiOutput() mainly because (for other reasons) it has
`display:contents`, which breaks the ::after positioning.
Note that, even if we could position it, we'd probably want to disable it
if it has recalculating children.
*/
&.shiny-html-output::after {
display: none;
}
}
}
/* Styles for the page-level pulse banner */
@mixin shiny-page-busy {
/* ui.busy_indicators.pulse_options() */
--_shiny-pulse-background: var(
--shiny-pulse-background,
linear-gradient(
120deg,
var(--bs-body-bg, #fff),
var(--bs-indigo, #4b00c1),
var(--bs-purple, #74149c),
var(--bs-pink, #bf007f),
var(--bs-body-bg, #fff)
)
);
--_shiny-pulse-height: var(--shiny-pulse-height, 5px);
--_shiny-pulse-speed: var(--shiny-pulse-speed, 1.85s);
/* Color, sizing, & positioning */
position: fixed;
top: 0;
left: 0;
height: var(--_shiny-pulse-height);
background: var(--_shiny-pulse-background);
z-index: 9999;
/* Animation */
animation-name: busy-page-pulse;
animation-duration: var(--_shiny-pulse-speed);
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
content: ""; /* Used in a ::after context */
}
/*
In spinners+pulse mode (the recommended default), show a page-level banner if the
page is busy, but there are no recalculating elements.
*/
[data-shiny-busy-spinners][data-shiny-busy-pulse] {
&.shiny-busy::after {
@include shiny-page-busy;
}
&.shiny-busy:has(.recalculating)::after {
display: none;
}
&.shiny-busy:has(#shiny-disconnected-overlay)::after {
display: none;
}
}
/* In pulse _only_ mode, show a page-level banner whenever shiny is busy. */
[data-shiny-busy-pulse]:not([data-shiny-busy-spinners]) {
&.shiny-busy::after {
@include shiny-page-busy;
}
&.shiny-busy:has(#shiny-disconnected-overlay)::after {
display: none;
}
}
/* Keyframes for the fading spinner */
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* Keyframes for the pulsing banner */
@keyframes busy-page-pulse {
0% {
left: -75%;
width: 75%;
}
50% {
left: 100%;
width: 75%;
}
/* Go back */
100% {
left: -75%;
width: 75%;
}
}

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import { hasDefinedProperty } from "../../utils";
import { InputBinding } from "./inputBinding";
import { hasDefinedProperty } from "../../utils";
type CheckedHTMLElement = HTMLInputElement;

View File

@@ -1,8 +1,8 @@
import $ from "jquery";
import { $escape, hasDefinedProperty, updateLabel } from "../../utils";
import type { CheckedHTMLElement } from "./checkbox";
import { InputBinding } from "./inputBinding";
import { $escape, updateLabel, hasDefinedProperty } from "../../utils";
import type { CheckedHTMLElement } from "./checkbox";
type CheckboxGroupHTMLElement = CheckedHTMLElement;
type ValueLabelObject = {

View File

@@ -1,13 +1,13 @@
import $ from "jquery";
import { InputBinding } from "./inputBinding";
import {
$escape,
formatDateUTC,
hasDefinedProperty,
parseDate,
updateLabel,
$escape,
parseDate,
hasDefinedProperty,
} from "../../utils";
import type { NotUndefined } from "../../utils/extraTypes";
import { InputBinding } from "./inputBinding";
declare global {
interface JQuery {

View File

@@ -1,7 +1,7 @@
import $ from "jquery";
import { InputBinding } from "./inputBinding";
import { FileUploader } from "../../file/fileProcessor";
import { shinyShinyApp } from "../../shiny/initedMethods";
import { InputBinding } from "./inputBinding";
const zoneActive = "shiny-file-input-active";
const zoneOver = "shiny-file-input-over";

View File

@@ -2,20 +2,20 @@ import { BindingRegistry } from "../registry";
import { InputBinding } from "./inputBinding";
import { ActionButtonInputBinding } from "./actionbutton";
import { CheckboxInputBinding } from "./checkbox";
import { CheckboxGroupInputBinding } from "./checkboxgroup";
import { DateInputBinding } from "./date";
import { DateRangeInputBinding } from "./daterange";
import { FileInputBinding } from "./fileinput";
import { NumberInputBinding } from "./number";
import { PasswordInputBinding } from "./password";
import { RadioInputBinding } from "./radio";
import { SelectInputBinding } from "./selectInput";
import { SliderInputBinding } from "./slider";
import { BootstrapTabInputBinding } from "./tabinput";
import { TextInputBinding } from "./text";
import { TextareaInputBinding } from "./textarea";
import { RadioInputBinding } from "./radio";
import { DateInputBinding } from "./date";
import { SliderInputBinding } from "./slider";
import { DateRangeInputBinding } from "./daterange";
import { SelectInputBinding } from "./selectInput";
import { ActionButtonInputBinding } from "./actionbutton";
import { BootstrapTabInputBinding } from "./tabinput";
import { FileInputBinding } from "./fileinput";
// TODO-barret make this an init method
type InitInputBindings = {

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import { $escape, hasDefinedProperty, updateLabel } from "../../utils";
import { InputBinding } from "./inputBinding";
import { $escape, hasDefinedProperty, updateLabel } from "../../utils";
type RadioHTMLElement = HTMLInputElement;

View File

@@ -1,7 +1,7 @@
import $ from "jquery";
import { InputBinding } from "./inputBinding";
import { $escape, hasDefinedProperty, updateLabel } from "../../utils";
import { indirectEval } from "../../utils/eval";
import { InputBinding } from "./inputBinding";
type SelectHTMLElement = HTMLSelectElement & { nonempty: boolean };
@@ -154,7 +154,7 @@ class SelectInputBinding extends InputBinding {
selectize.settings.load = function (query: string, callback: CallbackFn) {
const settings = selectize.settings;
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-floating-promises */
$.ajax({
url: data.url,
data: {

View File

@@ -5,10 +5,10 @@ import type {
import $ from "jquery";
// import { NameValueHTMLElement } from ".";
import {
$escape,
formatDateUTC,
hasDefinedProperty,
updateLabel,
$escape,
hasDefinedProperty,
} from "../../utils";
import type { TextHTMLElement } from "./text";

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import { hasDefinedProperty, isBS3 } from "../../utils";
import { InputBinding } from "./inputBinding";
import { hasDefinedProperty, isBS3 } from "../../utils";
type TabInputReceiveMessageData = { value?: string };

View File

@@ -1,5 +1,5 @@
import $ from "jquery";
import { $escape, hasDefinedProperty, updateLabel } from "../../utils";
import { $escape, updateLabel, hasDefinedProperty } from "../../utils";
import { InputBinding } from "./inputBinding";
@@ -122,4 +122,5 @@ class TextInputBinding extends TextInputBindingBase {
}
export { TextInputBinding, TextInputBindingBase };
export type { TextHTMLElement, TextReceiveMessageData };

View File

@@ -1,11 +1,11 @@
import $ from "jquery";
import { OutputBinding } from "./outputBinding";
import { shinyUnbindAll } from "../../shiny/initedMethods";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { debounce } from "../../time";
import { escapeHTML } from "../../utils";
import { indirectEval } from "../../utils/eval";
import { OutputBinding } from "./outputBinding";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
class DatatableOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement> {

View File

@@ -7,17 +7,7 @@ class DownloadLinkOutputBinding extends OutputBinding {
return $(scope).find("a.shiny-download-link");
}
renderValue(el: HTMLElement, data: string): void {
el.setAttribute("href", data);
el.classList.remove("disabled");
el.removeAttribute("aria-disabled");
el.removeAttribute("tabindex");
}
// Progress shouldn't be shown on the download button
// (progress will be shown as a page level pulse instead)
showProgress(el: HTMLElement, show: boolean): void {
return;
el;
show;
$(el).attr("href", data);
}
}

View File

@@ -1,9 +1,9 @@
import $ from "jquery";
import { OutputBinding } from "./outputBinding";
import { shinyUnbindAll } from "../../shiny/initedMethods";
import { renderContentAsync } from "../../shiny/render";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { OutputBinding } from "./outputBinding";
class HtmlOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement> {

View File

@@ -1,4 +1,5 @@
import $ from "jquery";
import { OutputBinding } from "./outputBinding";
import {
createBrushHandler,
createClickHandler,
@@ -7,17 +8,16 @@ import {
disableDrag,
initCoordmap,
} from "../../imageutils";
import type { CoordmapInit } from "../../imageutils/initCoordmap";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import {
strToBool,
getComputedLinkColor,
getStyle,
hasOwnProperty,
strToBool,
} from "../../utils";
import { IEVersion, isIE } from "../../utils/browser";
import { isIE, IEVersion } from "../../utils/browser";
import type { CoordmapInit } from "../../imageutils/initCoordmap";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { ifUndefined } from "../../utils/object";
import { OutputBinding } from "./outputBinding";
class ImageOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement> {

View File

@@ -1,9 +1,9 @@
import { TextOutputBinding } from "./text";
import { BindingRegistry } from "../registry";
import { DatatableOutputBinding } from "./datatable";
import { DownloadLinkOutputBinding } from "./downloadlink";
import { DatatableOutputBinding } from "./datatable";
import { HtmlOutputBinding } from "./html";
import { imageOutputBinding } from "./image";
import { TextOutputBinding } from "./text";
import { OutputBinding } from "./outputBinding";

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { asArray } from "../../utils";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
class OutputBinding {
name!: string;

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { css, html, LitElement } from "lit";
import { LitElement, html, css } from "lit";
import { ShinyClientError } from "../shiny/error";
const buttonStyles = css`

View File

@@ -1,8 +1,8 @@
import $ from "jquery";
import { triggerFileInputChanged } from "../events/inputChanged";
import { getFileInputBinding } from "../shiny/initedMethods";
import type { ShinyApp } from "../shiny/shinyapp";
import { $escape } from "../utils";
import type { ShinyApp } from "../shiny/shinyapp";
import { getFileInputBinding } from "../shiny/initedMethods";
type JobId = string;
type UploadUrl = string;
@@ -180,7 +180,7 @@ class FileUploader extends FileProcessor {
onFile(file: File, cont: () => void): void {
this.onProgress(file, 0);
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-floating-promises */
$.ajax(this.uploadUrl, {
type: "POST",
cache: false,

View File

@@ -1,7 +1,7 @@
import $ from "jquery";
import { equal, isnan, mapValues, roundSignif } from "../utils";
import type { Coordmap } from "./initCoordmap";
import { findOrigin } from "./initCoordmap";
import { equal, isnan, mapValues, roundSignif } from "../utils";
import type { Panel } from "./initPanelScales";
import type { Offset } from "./findbox";
@@ -656,4 +656,5 @@ function createBrush(
}
export { createBrush };
export type { Bounds, BrushOpts, BoundsCss };

View File

@@ -1,13 +1,13 @@
import $ from "jquery";
import { imageOutputBinding } from "../bindings/output/image";
import type { InputRatePolicy } from "../inputPolicies";
import { shinySetInputValue } from "../shiny/initedMethods";
import { Debouncer, Throttler } from "../time";
import type { Bounds, BoundsCss, BrushOpts } from "./createBrush";
import { createBrush } from "./createBrush";
import type { BoundsCss, Bounds, BrushOpts } from "./createBrush";
import type { Offset } from "./findbox";
import type { Coordmap } from "./initCoordmap";
import type { Panel } from "./initPanelScales";
import type { InputRatePolicy } from "../inputPolicies";
// ----------------------------------------------------------
// Handler creators for click, hover, brush.

View File

@@ -1,9 +1,9 @@
import { createBrush } from "./createBrush";
import { createClickInfo } from "./createClickInfo";
import {
createBrushHandler,
createClickHandler,
createHoverHandler,
createBrushHandler,
} from "./createHandlers";
import { disableDrag } from "./disableDrag";
import { findBox } from "./findbox";

View File

@@ -1,8 +1,8 @@
import $ from "jquery";
import { shinySetInputValue } from "../shiny/initedMethods";
import { mapValues } from "../utils";
import type { Bounds } from "./createBrush";
import type { Offset } from "./findbox";
import type { Bounds } from "./createBrush";
import type { Panel, PanelInit } from "./initPanelScales";
import { initPanelScales } from "./initPanelScales";

View File

@@ -1,8 +1,8 @@
// Map a value x from a domain to a range. If clip is true, clip it to the
import type { Offset } from "./findbox";
import { mapValues } from "../utils";
import type { Bounds } from "./createBrush";
import type { Offset } from "./findbox";
// range.
function mapLinear(

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import { isIE, setIEVersion, setIsIE, setIsQt } from "../utils/browser";
import { isIE, setIsQt, setIsIE, setIEVersion } from "../utils/browser";
import { userAgent } from "../utils/userAgent";
function getIEVersion() {

View File

@@ -1,10 +1,10 @@
import { determineBrowserInfo } from "./browser";
import { disableFormSubmission } from "./disableForm";
import { trackHistory } from "./history";
import { determineBrowserInfo } from "./browser";
import { windowShiny } from "../window/libraries";
import { setShiny } from "../shiny";
import { setUserAgent } from "../utils/userAgent";
import { windowShiny } from "../window/libraries";
import { windowUserAgent } from "../window/userAgent";
import { initReactlog } from "../shiny/reactlog";

View File

@@ -1,11 +1,12 @@
import { InputBatchSender } from "./inputBatchSender";
import { InputDeferDecorator } from "./inputDeferDecorator";
import { InputEventDecorator } from "./inputEventDecorator";
import { InputNoResendDecorator } from "./inputNoResendDecorator";
import { InputEventDecorator } from "./inputEventDecorator";
import { InputRateDecorator } from "./inputRateDecorator";
import { InputDeferDecorator } from "./inputDeferDecorator";
import { InputValidateDecorator } from "./inputValidateDecorator";
import type { EventPriority, InputPolicy } from "./inputPolicy";
import type { InputPolicy } from "./inputPolicy";
import type { EventPriority } from "./inputPolicy";
import type { InputRatePolicy } from "./inputRatePolicy";
export {
@@ -16,4 +17,5 @@ export {
InputDeferDecorator,
InputValidateDecorator,
};
export type { InputPolicy, EventPriority, InputRatePolicy };

View File

@@ -1,5 +1,5 @@
import type { ShinyApp } from "../shiny/shinyapp";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import type { ShinyApp } from "../shiny/shinyapp";
// Schedules data to be sent to shinyapp at the next setTimeout(0).
// Batches multiple input calls into one websocket message.

View File

@@ -1,9 +1,6 @@
import type { EventPriority } from "./inputPolicy";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import { hasDefinedProperty } from "../utils";
import type {
EventPriority,
InputPolicy,
InputPolicyOpts,
} from "./inputPolicy";
class InputDeferDecorator implements InputPolicy {
pendingInput: {

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import type { ShinyEventInputChanged } from "../events/shinyEvents";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import type { ShinyEventInputChanged } from "../events/shinyEvents";
import { splitInputNameType } from "./splitInputNameType";
class InputEventDecorator implements InputPolicy {

View File

@@ -1,5 +1,5 @@
import { hasDefinedProperty } from "../utils";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import { hasDefinedProperty } from "../utils";
import { splitInputNameType } from "./splitInputNameType";
type LastSentValues = { [key: string]: { [key: string]: string } };

View File

@@ -1,7 +1,7 @@
import { Debouncer, Invoker, Throttler } from "../time";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import type { InputRatePolicy } from "./inputRatePolicy";
import { Debouncer, Invoker, Throttler } from "../time";
import { splitInputNameType } from "./splitInputNameType";
import type { InputRatePolicy } from "./inputRatePolicy";
type RatePolicyModes = "debounce" | "direct" | "throttle";
@@ -66,4 +66,5 @@ class InputRateDecorator implements InputPolicy {
}
export { InputRateDecorator };
export type { RatePolicyModes };

View File

@@ -6,9 +6,9 @@ import type {
InputRateDecorator,
InputValidateDecorator,
} from "../inputPolicies";
import { ShinyClientError } from "./error";
import { shinyAppBindOutput, shinyAppUnbindOutput } from "./initedMethods";
import { sendImageSizeFns } from "./sendImageSize";
import { ShinyClientError } from "./error";
type BindScope = HTMLElement | JQuery<HTMLElement>;
@@ -320,10 +320,6 @@ async function bindOutputs(
$el.addClass("shiny-bound-output");
if (!$el.attr("aria-live")) $el.attr("aria-live", "polite");
if (Shiny.shinyapp?.$outputProgress.isRecalculating(id)) {
bindingAdapter.showProgress(true);
}
bindingsRegistry.addBinding(id, "output");
$el.trigger({
type: "shiny:bound",
@@ -464,4 +460,5 @@ async function bindAll(
}
export { unbindAll, bindAll, _bindAll };
export type { BindScope, BindInputsCtx };

View File

@@ -1,33 +1,33 @@
import $ from "jquery";
import { InputBinding, OutputBinding } from "../bindings";
import { initInputBindings } from "../bindings/input";
import { initOutputBindings } from "../bindings/output";
import { showErrorInClientConsole } from "../components/errorConsole";
import { resetBrush } from "../imageutils/resetBrush";
import { $escape, compareVersion } from "../utils";
import { showNotification, removeNotification } from "./notifications";
import { showModal, removeModal } from "./modal";
import { showReconnectDialog, hideReconnectDialog } from "./reconnectDialog";
import {
renderContentAsync,
renderContent,
renderDependenciesAsync,
renderDependencies,
renderHtmlAsync,
renderHtml,
} from "./render";
import { initShiny } from "./init";
import type {
shinyBindAll,
shinyForgetLastInputValue,
shinyInitializeInputs,
shinySetInputValue,
shinyInitializeInputs,
shinyUnbindAll,
} from "./initedMethods";
import { setFileInputBinding } from "./initedMethods";
import { removeModal, showModal } from "./modal";
import { removeNotification, showNotification } from "./notifications";
import { hideReconnectDialog, showReconnectDialog } from "./reconnectDialog";
import {
renderContent,
renderContentAsync,
renderDependencies,
renderDependenciesAsync,
renderHtml,
renderHtmlAsync,
} from "./render";
import type { Handler, ShinyApp } from "./shinyapp";
import { addCustomMessageHandler } from "./shinyapp";
import { initInputBindings } from "../bindings/input";
import { initOutputBindings } from "../bindings/output";
import { showErrorInClientConsole } from "../components/errorConsole";
interface Shiny {
version: string;
@@ -138,4 +138,5 @@ function setShiny(windowShiny_: Shiny): void {
}
export { windowShiny, setShiny };
export type { Shiny };

View File

@@ -1,6 +1,5 @@
import $ from "jquery";
import type { Shiny } from ".";
import type { InputPolicy } from "../inputPolicies";
import {
InputBatchSender,
InputDeferDecorator,
@@ -9,7 +8,7 @@ import {
InputRateDecorator,
InputValidateDecorator,
} from "../inputPolicies";
import type { InputPolicyOpts } from "../inputPolicies/inputPolicy";
import type { InputPolicy } from "../inputPolicies";
import { addDefaultInputOpts } from "../inputPolicies/inputValidateDecorator";
import { debounce, Debouncer } from "../time";
import {
@@ -19,13 +18,14 @@ import {
mapValues,
pixelRatio,
} from "../utils";
import type { BindInputsCtx, BindScope } from "./bind";
import { bindAll, unbindAll, _bindAll } from "./bind";
import type { BindInputsCtx, BindScope } from "./bind";
import { setShinyObj } from "./initedMethods";
import { registerDependency } from "./render";
import { sendImageSizeFns } from "./sendImageSize";
import { ShinyApp } from "./shinyapp";
import { registerNames as singletonsRegisterNames } from "./singletons";
import type { InputPolicyOpts } from "../inputPolicies/inputPolicy";
// "init_shiny.js"
async function initShiny(windowShiny: Shiny): Promise<void> {

View File

@@ -3,7 +3,8 @@ import $ from "jquery";
import { $escape, randomId } from "../utils";
import { shinyUnbindAll } from "./initedMethods";
import type { HtmlDep } from "./render";
import { renderContentAsync, renderDependenciesAsync } from "./render";
import { renderDependenciesAsync } from "./render";
import { renderContentAsync } from "./render";
// Milliseconds to fade in or out
const fadeDuration = 250;

View File

@@ -1,280 +0,0 @@
/*
* A state machine for tracking Shiny output progress.
*
* Although there are a handful of possible states, the ultimate goal here is to
* be able to say whether a given output `isRecalculating()` or not (and thus,
* whether we should show progress indication or not).
*
* The diagram below depicts the state machine. Each node represents a possible
* state and each edge represents a server-->client message that moves outputs
* from one state to another. If a node name is all caps, then the output should
* be showing a busy state when visible (i.e., `binding.showProgress(true)`).
*
* A more polished SVG version of this diagram can be found here:
* https://github.com/rstudio/shiny/blob/main/inst/diagrams/outputProgressStateMachine.svg
*
* +---------+ recalculating +---------+
* | INITIAL +--------------->| RUNNING |<----------------+
* +---------+ +---+-----+ |
* +-----------/ | |
* | recalculated |
* | | |
* | +--v---+---------------+ |
* | +--+ IDLE +--+-------+ | |
* | | +------+ | | | |
* 1 | 2| 3| 4| | |
* v v v v | |
* +------------+ +------+ +-----+ +-----+ | |
* | PERSISTENT | |cancel| |value| |error| | |
* +-------+----+ +---+--+ +-+---+ +-+---+ | |
* | 5| 5| | | |
* 5| v v 5| | |
* | +-------------+ | | |
* +------>| INVALIDATED |<-----+ | |
* +-----+-------+<-----------+ |
* | |
* | recalculating |
* +-----------------------+
*
* 1. {progress: {type: "binding", message: {persistent: true}}}
* 2. No message
* 3. Value
* 4. Error
* 5. {progress: {type: "binding"}}
*/
// The possible states of a given output.
enum OutputStates {
Initial = "initial",
Running = "running",
Idle = "idle",
Value = "value",
Error = "error",
Cancel = "cancel",
Persistent = "persistent",
Invalidated = "invalidated",
}
// Server->client messages that have an impact on output progress state.
// These derive from the Session's defineOutput() method.
type RecalculatingMessage = {
recalculating: {
name: string;
status: "recalculated" | "recalculating";
};
};
type FlushMessage = {
errors: { [key: string]: unknown };
values: { [key: string]: unknown };
inputMessages: [];
};
type ProgressMessage = {
progress: {
type: "binding";
message: {
id: string;
persistent: boolean;
};
};
};
// A generic server->client message type.
type Message = { [key: string]: unknown };
// The state machine that tracks the progress of outputs in a Shiny app.
class OutputProgressReporter {
private outputStates: Map<string, OutputStates> = new Map();
// A map of outputs that have changed their progress status since the last call to takeChanges().
// The value is true if the output is recalculating, and false otherwise.
private changedOutputs: Map<string, boolean> = new Map();
takeChanges(): Map<string, boolean> {
const result = this.changedOutputs;
this.changedOutputs = new Map();
return result;
}
// Returns whether the output is recalculating or not.
isRecalculating(name: string): boolean {
const state = this.#getState(name);
// The blue nodes in the state machine diagram
const recalculatingStates = [
OutputStates.Initial,
OutputStates.Running,
OutputStates.Idle,
OutputStates.Persistent,
OutputStates.Invalidated,
];
return recalculatingStates.includes(state);
}
// Update output state based on the message received from the server.
// Note that any message can be passed to this method, but only the
// messages that are relevant to output progress do anything to the state.
updateStateFromMessage(message: Message): void {
if (isRecalculatingMessage(message)) {
// The "1st level" of the state machine diagram
this.#updateStateFromRecalculating(message);
}
if (isFlushMessage(message)) {
// The "2nd level" of the state machine diagram
this.#updateStateFromFlush(message);
}
if (isProgressMessage(message)) {
// The "3rd level" of the state machine diagram
this.#updateStateFromProgress(message);
}
}
#updateStateFromRecalculating(message: RecalculatingMessage): void {
const { name, status } = message.recalculating;
const state = this.#getState(name);
if (status === "recalculating") {
switch (state) {
case OutputStates.Initial:
case OutputStates.Invalidated:
this.#setState(name, OutputStates.Running);
break;
default:
throw new Error(
`Shiny server sent a message that the output '${name}' is recalculating,
but the output is in an unexpected state of: '${state}'.`
);
}
}
if (status === "recalculated") {
switch (state) {
case OutputStates.Running:
this.#setState(name, OutputStates.Idle);
break;
default:
throw new Error(
`Shiny server sent a message that the output '${name}' has been recalculated,
but the output is in an unexpected state of: '${state}'.`
);
}
}
}
#updateStateFromFlush(message: FlushMessage): void {
for (const name in message.values) {
this.#updateStateFromValueOrError(name, OutputStates.Value);
}
for (const name in message.errors) {
this.#updateStateFromValueOrError(name, OutputStates.Error);
}
// Since req(F, cancelOutput = TRUE) doesn't send a message, we need to identify
// the situation by looking for outputs that are still idle and move them to cancel.
for (const [name, state] of this.outputStates) {
switch (state) {
case OutputStates.Idle:
this.#setState(name, OutputStates.Cancel);
break;
case OutputStates.Value:
case OutputStates.Error:
case OutputStates.Cancel:
case OutputStates.Persistent:
case OutputStates.Invalidated: // If the output is suspended
break;
default:
throw new Error(
`Shiny server sent a flush message, and after processing the values and errors,
the output '${name}' has an unexpected ending state of: '${state}'.`
);
}
}
}
#updateStateFromProgress(message: ProgressMessage): void {
const { id, persistent } = message.progress.message;
const state = this.#getState(id);
if (persistent) {
switch (state) {
case OutputStates.Running:
this.#setState(id, OutputStates.Persistent);
break;
default:
throw new Error(
`Shiny server has sent a 'persistent progress' message for ${id},
but the output is in an unexpected state of: ${state}`
);
}
} else {
switch (state) {
case OutputStates.Value:
case OutputStates.Error:
case OutputStates.Cancel:
case OutputStates.Persistent:
case OutputStates.Idle:
this.#setState(id, OutputStates.Invalidated);
break;
default:
throw new Error(
`Shiny server has sent a progress message for ${id},
but the output is in an unexpected state of: ${state}`
);
}
}
}
// When receiving values/errors as part of a flush message, outputs should generally
// be moving from Idle to Value/Error state.
#updateStateFromValueOrError(
name: string,
type: OutputStates.Error | OutputStates.Value
): void {
const state = this.#getState(name);
switch (state) {
case OutputStates.Idle:
this.#setState(name, type);
break;
default:
throw new Error(
`Shiny server has sent a ${type} for the output '${name}',
but the output is in an unexpected state of: '${state}'.`
);
}
}
#getState(name: string): OutputStates {
return this.outputStates.get(name) ?? OutputStates.Initial;
}
#setState(name: string, state: OutputStates): void {
const oldRecalc = this.isRecalculating(name);
this.outputStates.set(name, state);
const newRecalc = this.isRecalculating(name);
if (oldRecalc !== newRecalc) {
this.changedOutputs.set(name, newRecalc);
}
}
}
// Type guards
function isRecalculatingMessage(x: Message): x is RecalculatingMessage {
const m = x as RecalculatingMessage;
return m.recalculating !== undefined;
}
function isFlushMessage(x: Message): x is FlushMessage {
const m = x as FlushMessage;
return m.values !== undefined && m.errors !== undefined;
}
function isProgressMessage(x: Message): x is ProgressMessage {
const m = x as ProgressMessage;
return m.progress !== undefined && m.progress.type === "binding";
}
export { OutputProgressReporter };

View File

@@ -50,14 +50,13 @@ function initReactlog(): void {
window.escape(shinyAppConfig().sessionId);
// send notification
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-floating-promises */
$.get(url, function (result: "marked" | void) {
if (result !== "marked") return;
const html =
'<span id="shiny-reactlog-mark-text">Marked time point in reactlog</span>';
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
showNotification({
html: html,
closeButton: true,

View File

@@ -1,6 +1,6 @@
import $ from "jquery";
import { removeNotification, showNotification } from "./notifications";
import { showNotification, removeNotification } from "./notifications";
function updateTime(reconnectTime: number): void {
const $time = $("#shiny-reconnect-time");

View File

@@ -9,8 +9,8 @@ import {
} from "./initedMethods";
import { sendImageSizeFns } from "./sendImageSize";
import type { WherePosition } from "./singletons";
import { renderHtml as singletonsRenderHtml } from "./singletons";
import type { WherePosition } from "./singletons";
// There are synchronous and asynchronous versions of the exported functions
// renderContent(), renderHtml(), and renderDependencies(). This is because they

View File

@@ -1,19 +1,5 @@
import $ from "jquery";
import type { InputBinding } from "../bindings";
import type { OutputBindingAdapter } from "../bindings/outputAdapter";
import { showErrorInClientConsole } from "../components/errorConsole";
import type {
ShinyEventError,
ShinyEventMessage,
ShinyEventUpdateInput,
ShinyEventValue,
} from "../events/shinyEvents";
import type { UploadEndValue, UploadInitValue } from "../file/fileProcessor";
import { resetBrush } from "../imageutils/resetBrush";
import { $escape, hasOwnProperty, randomId, scopeExprToFunc } from "../utils";
import { AsyncQueue } from "../utils/asyncQueue";
import { isQt } from "../utils/browser";
import { indirectEval } from "../utils/eval";
import {
getShinyCreateWebsocket,
getShinyOnCustomMessage,
@@ -21,14 +7,26 @@ import {
shinyForgetLastInputValue,
shinyUnbindAll,
} from "./initedMethods";
import { removeModal, showModal } from "./modal";
import { removeNotification, showNotification } from "./notifications";
import { hideReconnectDialog, showReconnectDialog } from "./reconnectDialog";
import type { HtmlDep } from "./render";
import { isQt } from "../utils/browser";
import { showNotification, removeNotification } from "./notifications";
import { showModal, removeModal } from "./modal";
import { renderContentAsync, renderHtmlAsync } from "./render";
import type { HtmlDep } from "./render";
import { hideReconnectDialog, showReconnectDialog } from "./reconnectDialog";
import { resetBrush } from "../imageutils/resetBrush";
import type { OutputBindingAdapter } from "../bindings/outputAdapter";
import type {
ShinyEventError,
ShinyEventMessage,
ShinyEventValue,
ShinyEventUpdateInput,
} from "../events/shinyEvents";
import type { InputBinding } from "../bindings";
import { indirectEval } from "../utils/eval";
import type { WherePosition } from "./singletons";
import { OutputProgressReporter } from "./outputProgress";
import type { UploadInitValue, UploadEndValue } from "../file/fileProcessor";
import { AsyncQueue } from "../utils/asyncQueue";
import { showErrorInClientConsole } from "../components/errorConsole";
type ResponseValue = UploadEndValue | UploadInitValue;
type Handler = (message: any) => Promise<void> | void;
@@ -132,9 +130,7 @@ class ShinyApp {
// Output bindings
$bindings: { [key: string]: OutputBindingAdapter } = {};
// Output progress states
$outputProgress = new OutputProgressReporter();
$persistentProgress: Set<string> = new Set();
// Cached values/errors
$values: { [key: string]: any } = {};
@@ -245,7 +241,7 @@ class ShinyApp {
// This launches the action queue loop, which just runs in the background,
// so we don't need to await it.
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-floating-promises */
this.startActionQueueLoop();
};
socket.onmessage = (e) => {
@@ -363,7 +359,6 @@ class ShinyApp {
) {
const delay = this.reconnectDelay.next();
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
showReconnectDialog(delay);
this.$scheduleReconnect(delay);
}
@@ -661,9 +656,6 @@ class ShinyApp {
$(document).trigger(evt);
if (evt.isDefaultPrevented()) return;
// Before passing the message to handlers, use it to update output progress state
this.$outputProgress.updateStateFromMessage(evt.message);
// Send msgObj.foo and msgObj.bar to appropriate handlers
await this._sendMessagesToHandlers(
evt.message,
@@ -695,17 +687,13 @@ class ShinyApp {
}
}
// Call showProgress() on any output bindings that have changed their
// recalculating status since the last call to takeChanges().
// Note that we only need to call this function when a "flush" (i.e. "values")
// message or a "progress" message is received since these are the only
// two types of messages that can change the recalculating status. For more,
// see the state machine diagram in outputProgress.ts.
private _updateProgress() {
const changed = this.$outputProgress.takeChanges();
for (const [name, recalculating] of changed.entries()) {
if (hasOwnProperty(this.$bindings, name)) {
this.$bindings[name].showProgress(recalculating);
private _clearProgress() {
for (const name in this.$bindings) {
if (
hasOwnProperty(this.$bindings, name) &&
!this.$persistentProgress.has(name)
) {
this.$bindings[name].showProgress(false);
}
}
}
@@ -716,10 +704,11 @@ class ShinyApp {
// * However, `_sendMessagesToHandlers()` will adjust the `this` context to the same _`this`_.
addMessageHandler("values", async (message: { [key: string]: any }) => {
this._updateProgress();
this._clearProgress();
for (const key in message) {
if (hasOwnProperty(message, key)) {
this.$persistentProgress.delete(key);
await this.receiveOutput(key, message[key]);
}
}
@@ -730,6 +719,7 @@ class ShinyApp {
(message: { [key: string]: ErrorsMessageValue }) => {
for (const key in message) {
if (hasOwnProperty(message, key)) {
this.$persistentProgress.delete(key);
this.receiveError(key, message[key]);
}
}
@@ -799,9 +789,13 @@ class ShinyApp {
| { type: "show"; message: Parameters<typeof showNotification>[0] }
| { type: void }
) => {
if (message.type === "show") await showNotification(message.message);
else if (message.type === "remove") removeNotification(message.message);
else throw "Unkown notification type: " + message.type;
if (message.type === "show") {
await showNotification(message.message);
} else if (message.type === "remove") {
await Promise.resolve(() => removeNotification(message.message));
} else {
throw "Unknown notification type: " + message.type;
}
}
);
@@ -813,10 +807,14 @@ class ShinyApp {
| { type: "show"; message: Parameters<typeof showModal>[0] }
| { type: void }
) => {
if (message.type === "show") await showModal(message.message);
// For 'remove', message content isn't used
else if (message.type === "remove") removeModal();
else throw "Unkown modal type: " + message.type;
if (message.type === "show") {
await showModal(message.message);
} else if (message.type === "remove") {
// For 'remove', message content isn't used
await Promise.resolve(() => removeModal());
} else {
throw "Unknown modal type: " + message.type;
}
}
);
@@ -1435,9 +1433,13 @@ class ShinyApp {
binding: binding,
name: key,
});
if (binding.showProgress) binding.showProgress(true);
if (message.persistent) {
this.$persistentProgress.add(key);
} else {
this.$persistentProgress.delete(key);
}
}
this._updateProgress();
},
// Open a page-level progress bar

View File

@@ -1,4 +1,4 @@
import { debounce, Debouncer } from "./debounce";
import { Debouncer, debounce } from "./debounce";
import { Invoker } from "./invoke";
import { Throttler } from "./throttle";

View File

@@ -1,7 +1,7 @@
import $ from "jquery";
import { windowDevicePixelRatio } from "../window/pixelRatio";
import type { MapValuesUnion, MapWithResult } from "./extraTypes";
import { hasDefinedProperty, hasOwnProperty } from "./object";
import { hasOwnProperty, hasDefinedProperty } from "./object";
function escapeHTML(str: string): string {
/* eslint-disable @typescript-eslint/naming-convention */
@@ -14,7 +14,6 @@ function escapeHTML(str: string): string {
"'": "&#039;",
"/": "&#x2F;",
};
/* eslint-enable @typescript-eslint/naming-convention */
return str.replace(/[&<>'"/]/g, function (m) {
return escaped[m] as string;

View File

@@ -1,5 +1,5 @@
import type { CheckedHTMLElement } from "./checkbox";
import { InputBinding } from "./inputBinding";
import type { CheckedHTMLElement } from "./checkbox";
type CheckboxGroupHTMLElement = CheckedHTMLElement;
type ValueLabelObject = {
value: HTMLInputElement["value"];

View File

@@ -1,5 +1,5 @@
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { OutputBinding } from "./outputBinding";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
declare class DatatableOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement>;
onValueError(el: HTMLElement, err: ErrorsMessageValue): void;

View File

@@ -2,6 +2,5 @@ import { OutputBinding } from "./outputBinding";
declare class DownloadLinkOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement>;
renderValue(el: HTMLElement, data: string): void;
showProgress(el: HTMLElement, show: boolean): void;
}
export { DownloadLinkOutputBinding };

View File

@@ -1,6 +1,6 @@
import { OutputBinding } from "./outputBinding";
import { renderContentAsync } from "../../shiny/render";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { OutputBinding } from "./outputBinding";
declare class HtmlOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement>;
onValueError(el: HTMLElement, err: ErrorsMessageValue): void;

View File

@@ -1,6 +1,6 @@
import { OutputBinding } from "./outputBinding";
import type { CoordmapInit } from "../../imageutils/initCoordmap";
import type { ErrorsMessageValue } from "../../shiny/shinyapp";
import { OutputBinding } from "./outputBinding";
declare class ImageOutputBinding extends OutputBinding {
find(scope: HTMLElement): JQuery<HTMLElement>;
renderValue(el: HTMLElement, data: {

View File

@@ -1,5 +1,5 @@
/// <reference types="jquery" />
import type { Bounds, BoundsCss, BrushOpts } from "./createBrush";
import type { BoundsCss, Bounds, BrushOpts } from "./createBrush";
import type { Offset } from "./findbox";
import type { Coordmap } from "./initCoordmap";
import type { Panel } from "./initPanelScales";

View File

@@ -1,6 +1,6 @@
import { createBrush } from "./createBrush";
import { createClickInfo } from "./createClickInfo";
import { createBrushHandler, createClickHandler, createHoverHandler } from "./createHandlers";
import { createClickHandler, createHoverHandler, createBrushHandler } from "./createHandlers";
import { disableDrag } from "./disableDrag";
import { findBox } from "./findbox";
import { initCoordmap } from "./initCoordmap";

View File

@@ -1,6 +1,6 @@
/// <reference types="jquery" />
import type { Bounds } from "./createBrush";
import type { Offset } from "./findbox";
import type { Bounds } from "./createBrush";
import type { Panel, PanelInit } from "./initPanelScales";
declare function findOrigin($el: JQuery<HTMLElement>): Offset;
type OffsetCss = {

View File

@@ -1,5 +1,5 @@
import type { Bounds } from "./createBrush";
import type { Offset } from "./findbox";
import type { Bounds } from "./createBrush";
type PanelInit = {
domain: {
top: number;

View File

@@ -1,10 +1,11 @@
import { InputBatchSender } from "./inputBatchSender";
import { InputDeferDecorator } from "./inputDeferDecorator";
import { InputEventDecorator } from "./inputEventDecorator";
import { InputNoResendDecorator } from "./inputNoResendDecorator";
import { InputEventDecorator } from "./inputEventDecorator";
import { InputRateDecorator } from "./inputRateDecorator";
import { InputDeferDecorator } from "./inputDeferDecorator";
import { InputValidateDecorator } from "./inputValidateDecorator";
import type { EventPriority, InputPolicy } from "./inputPolicy";
import type { InputPolicy } from "./inputPolicy";
import type { EventPriority } from "./inputPolicy";
import type { InputRatePolicy } from "./inputRatePolicy";
export { InputBatchSender, InputEventDecorator, InputNoResendDecorator, InputRateDecorator, InputDeferDecorator, InputValidateDecorator, };
export type { InputPolicy, EventPriority, InputRatePolicy };

View File

@@ -1,5 +1,5 @@
import type { ShinyApp } from "../shiny/shinyapp";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
import type { ShinyApp } from "../shiny/shinyapp";
declare class InputBatchSender implements InputPolicy {
target: InputPolicy;
shinyapp: ShinyApp;

View File

@@ -1,4 +1,5 @@
import type { EventPriority, InputPolicy, InputPolicyOpts } from "./inputPolicy";
import type { EventPriority } from "./inputPolicy";
import type { InputPolicy, InputPolicyOpts } from "./inputPolicy";
declare class InputDeferDecorator implements InputPolicy {
pendingInput: {
[key: string]: {

View File

@@ -1,15 +1,15 @@
import { InputBinding, OutputBinding } from "../bindings";
import { initInputBindings } from "../bindings/input";
import { initOutputBindings } from "../bindings/output";
import { resetBrush } from "../imageutils/resetBrush";
import { $escape, compareVersion } from "../utils";
import type { shinyBindAll, shinyForgetLastInputValue, shinyInitializeInputs, shinySetInputValue, shinyUnbindAll } from "./initedMethods";
import { removeModal, showModal } from "./modal";
import { removeNotification, showNotification } from "./notifications";
import { hideReconnectDialog, showReconnectDialog } from "./reconnectDialog";
import { renderContent, renderContentAsync, renderDependencies, renderDependenciesAsync, renderHtml, renderHtmlAsync } from "./render";
import { showNotification, removeNotification } from "./notifications";
import { showModal, removeModal } from "./modal";
import { showReconnectDialog, hideReconnectDialog } from "./reconnectDialog";
import { renderContentAsync, renderContent, renderDependenciesAsync, renderDependencies, renderHtmlAsync, renderHtml } from "./render";
import type { shinyBindAll, shinyForgetLastInputValue, shinySetInputValue, shinyInitializeInputs, shinyUnbindAll } from "./initedMethods";
import type { Handler, ShinyApp } from "./shinyapp";
import { addCustomMessageHandler } from "./shinyapp";
import { initInputBindings } from "../bindings/input";
import { initOutputBindings } from "../bindings/output";
interface Shiny {
version: string;
$escape: typeof $escape;

View File

@@ -1,12 +0,0 @@
type Message = {
[key: string]: unknown;
};
declare class OutputProgressReporter {
#private;
private outputStates;
private changedOutputs;
takeChanges(): Map<string, boolean>;
isRecalculating(name: string): boolean;
updateStateFromMessage(message: Message): void;
}
export { OutputProgressReporter };

View File

@@ -1,6 +1,6 @@
import type { BindScope } from "./bind";
import type { WherePosition } from "./singletons";
import { renderHtml as singletonsRenderHtml } from "./singletons";
import type { WherePosition } from "./singletons";
declare function renderContentAsync(el: BindScope, content: string | {
html: string;
deps?: HtmlDep[];

View File

@@ -1,7 +1,6 @@
import type { OutputBindingAdapter } from "../bindings/outputAdapter";
import type { UploadEndValue, UploadInitValue } from "../file/fileProcessor";
import type { UploadInitValue, UploadEndValue } from "../file/fileProcessor";
import { AsyncQueue } from "../utils/asyncQueue";
import { OutputProgressReporter } from "./outputProgress";
type ResponseValue = UploadEndValue | UploadInitValue;
type Handler = (message: any) => Promise<void> | void;
type ShinyWebSocket = WebSocket & {
@@ -31,7 +30,7 @@ declare class ShinyApp {
$bindings: {
[key: string]: OutputBindingAdapter;
};
$outputProgress: OutputProgressReporter;
$persistentProgress: Set<string>;
$values: {
[key: string]: any;
};
@@ -76,7 +75,7 @@ declare class ShinyApp {
$updateConditionals(): void;
dispatchMessage(data: ArrayBufferLike | string): Promise<void>;
private _sendMessagesToHandlers;
private _updateProgress;
private _clearProgress;
private _init;
progressHandlers: {
binding: (this: ShinyApp, message: {

Some files were not shown because too many files have changed in this diff Show More