Compare commits

..

62 Commits

Author SHA1 Message Date
Garrick Aden-Buie
2f4bd63dbf docs: Update file path usage of spinner_type 2024-05-09 15:09:50 -04:00
Garrick Aden-Buie
62250b751d feat: base64-encode local spinner files 2024-05-09 15:06:43 -04:00
Garrick Aden-Buie
65a3536102 chore: fix collate order 2024-05-09 11:41:03 -04:00
Garrick Aden-Buie
f6ef2e39d1 feat: spinner_selector=NULL returns inline styles 2024-05-09 11:40:57 -04:00
Garrick Aden-Buie
0f99fba328 chore: Move spinners to dependency, use CSS vars only for spinner selection 2024-05-09 11:30:36 -04:00
Garrick Aden-Buie
9fb9004fa1 fix: use --shiny-spinner-url 2024-05-09 10:38:27 -04:00
Garrick Aden-Buie
a693096684 feat: add many spinner options
all the spinners from https://github.com/n3r4zzurr0/svg-spinners
2024-05-08 23:33:51 -04:00
Garrick Aden-Buie
c4fa6a74a1 fix: reduce specificity of .recalculating positioning 2024-05-08 23:13:58 -04:00
Carson
439f48ea4b Address feedback 2024-05-08 17:04:37 -05:00
cpsievert
9b78f7b706 devtools::document() (GitHub Actions) 2024-05-08 20:59:27 +00:00
Carson
f7ab2be2a3 Update snapshots 2024-05-08 15:57:00 -05:00
Carson Sievert
4348aaf717 Apply suggestions from code review
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2024-05-08 15:56:04 -05:00
Carson
f7ec5acda5 Merge branch 'main' into busy-indicators 2024-05-08 11:03:03 -05:00
Carson Sievert
2872c87e32 Allow for progress binding to move from Idle to Invalidated status (#4047)
* Close #4046: Allow for progress binding to move from Idle to Invalidated status

* `yarn build` (GitHub Actions)

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2024-05-07 17:46:46 -05:00
cpsievert
53edf198ae Sync package version (GitHub Actions) 2024-05-06 20:31:21 +00:00
cpsievert
5c73e0195c yarn build (GitHub Actions) 2024-05-06 20:30:10 +00:00
Carson
8238b299af Bump version 2024-05-06 15:25:18 -05:00
Carson
5c3430d96f Merge branch 'main' into busy-indicators 2024-05-06 09:39:37 -05:00
Carson Sievert
ecb591f2e1 Disable downloadLink()/downloadButton() until their href is ready (#4041)
* Close #3606: disable downloadLink()/downloadButton() until their href has been populated

* Update news
2024-05-06 09:36:59 -05:00
cpsievert
4e2e373f07 yarn build (GitHub Actions) 2024-05-03 20:08:46 +00:00
cpsievert
0e5baf01eb devtools::document() (GitHub Actions) 2024-05-03 20:06:59 +00:00
Carson
9c84bff757 Add to pkgdown reference 2024-05-03 15:04:10 -05:00
Carson
3d444d3ec3 Embed animation inside svg (to avoid Chromium bug). Consolidate options into a singular busyIndicatorOptions() 2024-05-03 14:08:53 -05:00
Carson
397fc6eff7 Revert "Use an actual div instead of a pseudo-element since chromium can't be trusted to show them when animated"
This reverts commit 6167c1dfd7.
2024-05-03 09:46:22 -05:00
Carson
6167c1dfd7 Use an actual div instead of a pseudo-element since chromium can't be trusted to show them when animated 2024-05-02 18:10:00 -05:00
Carson
c40f9f1de8 Bring in new spinner defaults 2024-05-02 18:08:17 -05:00
Carson
a0f3629bad Add useBusyIndicators(), spinnerOptions(), and pulseOptions() 2024-05-02 18:08:16 -05:00
cpsievert
7144e5cf74 yarn build (GitHub Actions) 2024-05-02 18:04:33 -05:00
Carson
4cc31df40d First pass at a proper state machine for managing output progress state 2024-05-02 18:04:32 -05:00
Carson Sievert
8e37d45948 Improve/fix output progress reporting (#4039)
* First pass at a proper state machine for managing output progress state

* `yarn build` (GitHub Actions)

* Improved naming

* Include ascii version of diagram (as well as the source file

* Update srcts/src/shiny/outputProgress.ts

Co-authored-by: Joe Cheng <joe@rstudio.com>

* `yarn build` (GitHub Actions)

* Only call showProgress for outputs that have actually changed their recalculating status

* Add some more commentary

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
Co-authored-by: Joe Cheng <joe@rstudio.com>
2024-05-02 18:01:29 -05:00
Winston Chang
c11f120bb9 Change eslint-disable comments to eslint-disable-next-line (#4037)
* Change eslint-disable comments to eslint-disable-next-line

* Allow floating promise

* `yarn build` (GitHub Actions)

---------

Co-authored-by: wch <wch@users.noreply.github.com>
2024-04-30 13:19:48 -05:00
Winston Chang
950c63049b Check that $socket exists before sending message (#4035)
* Check that socket exists before sending message

* `yarn build` (GitHub Actions)

---------

Co-authored-by: wch <wch@users.noreply.github.com>
2024-04-26 15:21:35 -05:00
Carson Sievert
3edf9bfad8 Fix opacity dimming on recalculating uiOutput() (#4028)
* Close #4027: Fix opacity dimming on recalculating uiOutput(). Also, only apply display:content when there are child elements

* Update inst/www/shared/shiny_scss/shiny.bootstrap5.scss

* Add news item
2024-04-10 13:16:41 -05:00
Carson Sievert
420a2c054c Start new version (#4023)
* Start new version

* `yarn build` (GitHub Actions)

* Sync package version (GitHub Actions)

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2024-04-03 10:03:31 -05:00
Carson Sievert
5e566a057d Start v1.8.1.1 release candidate (#4020)
* Start v1.8.1.1 release candidate

* `yarn build` (GitHub Actions)

* Sync package version (GitHub Actions)

* Remove alpha from npm version

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2024-04-03 09:26:01 -05:00
Carson Sievert
edd1db78e3 Warn instead of error when duplicate binding IDs are found in non-devmode (#4019)
* Close #4016. Warn instead of error when duplicate binding IDs are found in non-devmode

* Get rid of unreachable ShinyClientError()

* `yarn build` (GitHub Actions)

* Update srcts/src/shiny/bind.ts

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>

* `yarn build` (GitHub Actions)

* Move logic to where error gets thrown not constructed

* `yarn build` (GitHub Actions)

* Update NEWS

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2024-03-29 13:51:46 -05:00
Joe Cheng
47526a769a ExtendedTask should not be cloneable (#4015) 2024-03-27 19:06:21 -05:00
Carson Sievert
0474eeeead Start new version (#4014)
* Start new version

* `yarn build` (GitHub Actions)

* Sync package version (GitHub Actions)

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2024-03-27 10:10:45 -05:00
Carson Sievert
e8cdc78f0f v1.8.1 release candidate (#4008)
* Start v1.8.1 release candidate

* Update urls and yarn build

* Sync package version (GitHub Actions)

* Check-in revdep results

* Groom news

---------

Co-authored-by: cpsievert <cpsievert@users.noreply.github.com>
2024-03-27 10:01:08 -05:00
Carson Sievert
7742b652ba Fix and simplify reactlog's version check approach. (#4012)
* Close #4011. Fix and simplify reactlog's version check approach.

* Better variable name

* Use test_path() for consistent path location

* Just use packageDescription()

* Update tests/testthat/test-reactlog.R

* Update tests/testthat/test-reactlog.R

* Update DESCRIPTION
2024-03-22 17:39:52 -05:00
Carson Sievert
7ed68ed927 Revert changes to shinyDeprecated() & update renderDataTables() tests to always use shiny's datatables implementation (#4010)
* Revert "feat: Deprecate with warnings, expect `renderDataTable()` to be deprecated (#4007)"

This reverts commit a8c6065b9f.

* Use shiny's datatables implementation when testing
2024-03-22 17:35:15 -05:00
Garrick Aden-Buie
ac06350e08 chore: restyle new examples-shiny apps (#4004)
* chore: restyle examples-shiny

* chore: restore select newlines

* More consistent approach to whitespace

---------

Co-authored-by: Carson <cpsievert1@gmail.com>
2024-03-21 17:43:30 -05:00
Garrick Aden-Buie
43698f0860 feat: Run examples from any package (#4005)
* chore: `inst/shiny` -> `inst/examples-shiny`

* feat(runExamples): Find examples in any package

* refactor: code style

* refactor: small code style changes

* docs: fix runApp typo

* chore: include package name in valid examples message

* chore(runExample): check that `package` is installed

* chore: use braced package name

* Update news

---------

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2024-03-21 12:07:57 -05:00
avoidaway
c73e1a21b8 chore: remove repetitive words (#3999)
Signed-off-by: avoidaway <cmoman@126.com>
2024-03-21 11:30:24 -05:00
Garrick Aden-Buie
d855468398 chore: inst/shiny -> inst/examples-shiny (#4003) 2024-03-21 10:58:50 -05:00
Garrick Aden-Buie
b8efd88448 docs(MockShinySession): document unhandled error param (#4006) 2024-03-21 10:58:27 -05:00
Garrick Aden-Buie
a8c6065b9f feat: Deprecate with warnings, expect renderDataTable() to be deprecated (#4007)
* feat: Deprecate with a warning

Use `rlang::warn()` instead of `rlang::inform()` and use the lifecycle warning class so that lifecycle infrastructure works

* tests: expect that renderDataTable is deprecated

* tests: invert warning and error expectation
2024-03-21 10:57:50 -05:00
Carson Sievert
12a8b228d9 Follow up to #3998: correct version requirement in message. (#4002) 2024-03-21 09:12:01 -05:00
Sara Altman
47fb562151 Update examples to use bslib (#3963)
* update 01_hello

* Updates 06_tabsets example to use bslib

* Pre-emptively adds legacy versions of all of the original examples

* Switches tabset example to use navset_card_underline()

* Updates example 2

* Updates 03_reactivity

* Updates 04_mpg

* Updates 05_sliders

* Updates 07_widgets

* Deletes 08_html_legacy. Original example does not need updated.

* Updates 09_upload

* Updates 10_download

* Updates 11_timer

* Keep inst/example unchanged; add new examples under inst/shiny and update runExamples() to use that directory by default

* Update news

* Fix some code formatting issues

* Update NEWS.md

* Don't default to showcase mode

---------

Co-authored-by: Garrett Grolemund <grolemund@gmail.com>
Co-authored-by: Carson <cpsievert1@gmail.com>
2024-03-20 16:04:58 -05:00
Carson Sievert
f0059b71e5 Use bs-danger instead of bs-danger-text-emphasis for text color on error messages (#4001) 2024-03-20 12:18:05 -05:00
Carson Sievert
89aaa977e8 Update datatables.js from 1.10.5 to 1.10.22 and deprecate renderDataTable()/dataTableOutput() (#3998)
* Update datatables.js from 1.10.5 to 1.10.22. Deprecate renderDataTable()/DTOutput()

* Update news; go back to old types version

* Clean up

* Update NEWS.md

* Update NEWS.md
2024-03-19 14:50:15 -05:00
Kirill Müller
ae308e03ad Avoid R package warning in loadSupport() if autoload is disabled (#3513)
* Avoid bogus warning

* refactor: source globals first, then deal with helpers

* refactor: Factor out `warn_if_app_dir_is_package()` for readability

* chore: simplify diff

* docs(news): Add news item

* Hint to help file in message.

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>

---------

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2024-03-15 15:50:35 -05:00
Garrick Aden-Buie
c1a1542cfe fix(updateSelectizeInput): Clear current value before update if selected and sever = TRUE (#3967)
* fix(updateSelectizeInput): Clear current value before update if `selected` and `server = TRUE`

Fixes #3966

* chore: yarn build

* `yarn build` (GitHub Actions)

* docs(news): Add news item

* chore: Add comments for future selves

Co-authored-by: Carson Sievert <cpsievert1@gmail.com>

* `yarn build` (GitHub Actions)

---------

Co-authored-by: gadenbuie <gadenbuie@users.noreply.github.com>
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
2024-03-14 09:56:06 -05:00
Garrick Aden-Buie
3c4a908773 feat: Add onUnhandledError() (#3993)
* feat: Add `onUnhandledError()`

* docs(NEWS): Update previous news item

* docs(onUnhandledError): Add example

* docs(MockShinySession): Fix unhandledErrorCallbacks private field docs

* feat: Handle non-fatal unhandled errors, too

* docs(onUnhandledError): Add more detailed documentation

* `devtools::document()` (GitHub Actions)

* docs: Small edits
2024-03-14 10:21:59 -04:00
Garrick Aden-Buie
e2b7f91138 feat: Add shiny.error.unhandled error handler (#3989)
* feat(shiny.error.unhandled): Allow users to provide an unhandled error handler

* Extract `shinyUserErrorUnhandled()` to use in MockSession too

* tests(shiny.error.unhandled): Test that unhandled errors are handled safely

* docs: Clarify that session still ends with an unhandled error

* docs: Add news item
2024-03-08 13:36:36 -06:00
Garrick Aden-Buie
c73978cdd5 docs: update roxygen2 (#3988)
* fix: `@docType "package"` is deprecated

* fix: S3 methods need `@export` or `@exportS3method` tag.

* chore: devtools::document()
2024-03-08 09:15:37 -06:00
Andreas Deininger
6760c31818 Documentation: fixing typos (#3932)
* Documentation: fixing typos

* Commit changes after generation of package docs
2024-02-02 16:53:48 -06:00
olivroy
781ceaaa5c Remove ellipsis dependency (#3959)
* Remove ellipsis dependency

* Use the above `@importfrom rlang`

* move usethis namespace
2024-02-02 16:52:39 -06:00
Fenno Vermeij
fff283648b fix(downloadButton): Return tag directly (#2672)
* Fix `downloadButton()` not rendering in rmarkdown documents

---------

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
2024-01-30 17:31:40 -05:00
Winston Chang
f71f1256b8 Fix duplicate ID check logic (#3978)
* Fix duplicate ID logic

* Build shiny.js
2024-01-24 14:42:20 -06:00
Nick Strayer
f26b1335d8 Dev mode aware client and duplicate input/output ID handling updates (#3956)
* Add field with devmode status to the initial config object sent over on connection

* Add indicator of "devmode" status to the client via an injected script tag on load. This is modeled after what is done for showcase mode.

* Add logic to flag all duplicated IDs when in devmode

* Only show error console in devmode.

* Remove left-over devmode status in code

* `yarn build` (GitHub Actions)

* Build shiny.js

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

---------

Co-authored-by: nstrayer <nstrayer@users.noreply.github.com>
Co-authored-by: Winston Chang <winston@posit.co>
Co-authored-by: wch <wch@users.noreply.github.com>
2024-01-24 12:37:27 -06:00
Nick Strayer
370ba1f288 Make error console sizing constant across base and bslib apps (#3947)
* Add more encapsulated sizes using css variables instead of `rem` units so console is consistantly sized across apps that set the body font size.

* `yarn build` (GitHub Actions)

* `yarn build` (GitHub Actions)

* `devtools::document()` (GitHub Actions)

* `yarn build` (GitHub Actions)

---------

Co-authored-by: nstrayer <nstrayer@users.noreply.github.com>
Co-authored-by: jcheng5 <jcheng5@users.noreply.github.com>
Co-authored-by: Winston Chang <winston@posit.co>
Co-authored-by: wch <wch@users.noreply.github.com>
2024-01-22 14:17:10 -06:00
179 changed files with 4288 additions and 1255 deletions

View File

@@ -1,7 +1,7 @@
Package: shiny
Type: Package
Title: Web Application Framework for R
Version: 1.8.0.9000
Version: 1.8.1.9001
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"),
@@ -93,10 +93,10 @@ Imports:
glue (>= 1.3.2),
bslib (>= 0.3.0),
cachem,
ellipsis,
lifecycle (>= 0.2.0)
Suggests:
datasets,
DT,
Cairo (>= 1.5-5),
testthat (>= 3.0.0),
knitr (>= 1.6),
@@ -128,6 +128,8 @@ Collate:
'map.R'
'utils.R'
'bootstrap.R'
'busy-indicators-spinners.R'
'busy-indicators.R'
'cache-utils.R'
'deprecated.R'
'devmode.R'
@@ -204,7 +206,7 @@ Collate:
'version_selectize.R'
'version_strftime.R'
'viewer.R'
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RdMacros: lifecycle

View File

@@ -19,6 +19,7 @@ S3method("[[",shinyoutput)
S3method("[[<-",reactivevalues)
S3method("[[<-",shinyoutput)
S3method("names<-",reactivevalues)
S3method(as.list,Map)
S3method(as.list,reactivevalues)
S3method(as.shiny.appobj,character)
S3method(as.shiny.appobj,list)
@@ -43,6 +44,7 @@ S3method(bindEvent,reactiveExpr)
S3method(bindEvent,shiny.render.function)
S3method(format,reactiveExpr)
S3method(format,reactiveVal)
S3method(length,Map)
S3method(names,reactivevalues)
S3method(print,reactive)
S3method(print,reactivevalues)
@@ -76,6 +78,7 @@ export(br)
export(browserViewer)
export(brushOpts)
export(brushedPoints)
export(busyIndicatorOptions)
export(callModule)
export(captureStackTraces)
export(checkboxGroupInput)
@@ -189,6 +192,7 @@ export(onRestore)
export(onRestored)
export(onSessionEnded)
export(onStop)
export(onUnhandledError)
export(outputOptions)
export(p)
export(pageWithSidebar)
@@ -314,6 +318,7 @@ export(updateTextInput)
export(updateVarSelectInput)
export(updateVarSelectizeInput)
export(urlModal)
export(useBusyIndicators)
export(validate)
export(validateCssUnit)
export(varSelectInput)
@@ -333,8 +338,6 @@ import(httpuv)
import(methods)
import(mime)
import(xtable)
importFrom(ellipsis,check_dots_empty)
importFrom(ellipsis,check_dots_unnamed)
importFrom(fastmap,fastmap)
importFrom(fastmap,is.key_missing)
importFrom(fastmap,key_missing)
@@ -392,6 +395,8 @@ importFrom(rlang,"fn_body<-")
importFrom(rlang,"fn_fmls<-")
importFrom(rlang,as_function)
importFrom(rlang,as_quosure)
importFrom(rlang,check_dots_empty)
importFrom(rlang,check_dots_unnamed)
importFrom(rlang,enexpr)
importFrom(rlang,enquo)
importFrom(rlang,enquo0)

40
NEWS.md
View File

@@ -1,19 +1,47 @@
# shiny (development version)
## Breaking changes
* Both `conditionalPanel()` and `uiOutput()` are now styled with `display: contents` by default in Shiny apps that use Bootstrap 5. This means that the elements they contain are positioned as if they were direct children of the parent container holding the `conditionalPanel()` or `uiOutput()`. This is probably what most users intend when they use these functions, but it may break apps that applied styles directly to the container elements created by these two functions. In that case, you may include CSS rules to set `display: block` for the `.shiny-panel-conditional` or `.shiny-html-output` classes. (#3957, #3960)
## New features and improvements
* Added an console that shows some errors in the browser. Also provide better error messages for duplicate input and output bindings. (#3931)
* 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)
* Added a new `ExtendedTask` abstraction, for long-running asynchronous tasks that you don't want to block the rest of the app, or even the rest of the session. Designed to be used with new `bslib::input_task_button()` and `bslib::bind_task_button()` functions that help give user feedback and prevent extra button clicks. (#3958)
## 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
* In v1.8.1, shiny.js starting throwing an error when input/output bindings have duplicate IDs. This error is now only thrown when `shiny::devmode(TRUE)` is enabled, so the issue is still made discoverable through the JS error console, but avoids unnecessarily breaking apps that happen to work with duplicate IDs. (#4019)
# shiny 1.8.1
## New features and improvements
* Added `ExtendedTask`, a new simple way to launch long-running asynchronous tasks that are truly non-blocking. That is, even _within_ a session, an `ExtendedTask` won't block the main thread from flushing the reactive graph (i.e., UI updates won't be blocked). `ExtendedTask` pairs nicely with new `bslib::input_task_button()` and `bslib::bind_task_button()` functions, which help give user feedback and prevent extra button clicks. (#3958)
* Added a JavaScript error dialog, reporting errors that previously were only discoverable by opening the browser's devtools open. Since this dialog is mainly useful for debugging and development, it must be enabled with `shiny::devmode()`. (#3931)
* `runExamples()` now uses the `{bslib}` package to generate a better looking result. It also gains a `package` argument so that other packages can leverage this same function to run Shiny app examples. For more, see `?runExamples`. (#3963, #4005)
* Added `onUnhandledError()` to register a function that will be called when an unhandled error occurs in a Shiny app. Note that this handler doesn't stop the error or prevent the session from closing, but it can be used to log the error or to clean up session-specific resources. (thanks @JohnCoene, #3993)
## Changes
* `renderDataTable()`/`dataTableOutput()` are officially deprecated in favor of [their `{DT}` equivalents](https://rstudio.github.io/DT/shiny.html). Migrating to `{DT}`, in most cases, just requires changing `renderDataTable()` to `DT::renderDT()` and `dataTableOutput()` to `DT::DTOutput()`. Also, to promote migration, when a recent version of `{DT}` is available, `renderDataTable()`/`dataTableOutput()` now automatically use their `{DT}` equivalent (and provide a message that they are doing so). If this happens to degrade an existing app, set `options(shiny.legacy.datatable = TRUE)` to get the old (i.e., non-`{DT}`) implementation. (#3998)
* Both `conditionalPanel()` and `uiOutput()` are now styled with `display: contents` by default in Shiny apps that use Bootstrap 5. This means that the elements they contain are positioned as if they were direct children of the parent container holding the `conditionalPanel()` or `uiOutput()`. This is probably what most users intend when they use these functions, but it may break apps that applied styles directly to the container elements created by these two functions. In that case, you may include CSS rules to set `display: block` for the `.shiny-panel-conditional` or `.shiny-html-output` classes. (#3957, #3960)
## Bug fixes
* Notifications are now constrained to the width of the viewport for window widths smaller the default notification panel size. (#3949)
* Fixed #2392: `downloadButton()` now visibly returns its HTML tag so that it renders correctly in R Markdown and Quarto output. (Thanks to @fennovj, #2672)
* Calling `updateSelectizeInput()` with `choices` and `selected` now clears the current selection before updating the choices and selected value. (#3967)
* Loading a Shiny app in a package-like directory will no longer warn if autoloading is disabled by the presence of an `R/_disable_autoload.R` file. (Thanks to @krlmlr and @tanho63, #3513)
# shiny 1.8.0
## Breaking changes

View File

@@ -453,7 +453,7 @@ utils::globalVariables(".GenericCallEnv", add = TRUE)
#' bindEvent(input$go)
#' # The cached, eventified reactive takes a reactive dependency on
#' # input$go, but doesn't use it for the cache key. It uses input$x and
#' # input$y for the cache key, but doesn't take a reactive depdency on
#' # input$y for the cache key, but doesn't take a reactive dependency on
#' # them, because the reactive dependency is superseded by addEvent().
#'
#' output$txt <- renderText(r())

View File

@@ -551,7 +551,7 @@ restoreInput <- function(id, default) {
#' `window.history.pushState(null, null, queryString)`.
#'
#' @param queryString The new query string to show in the location bar.
#' @param mode When the query string is updated, should the the current history
#' @param mode When the query string is updated, should the current history
#' entry be replaced (default), or should a new history entry be pushed onto
#' the history stack? The former should only be used in a live bookmarking
#' context. The latter is useful if you want to navigate between states using

View File

@@ -1118,17 +1118,17 @@ tableOutput <- function(outputId) {
dataTableDependency <- list(
htmlDependency(
"datatables",
"1.10.5",
"1.10.22",
src = "www/shared/datatables",
package = "shiny",
script = "js/jquery.dataTables.min.js"
),
htmlDependency(
"datatables-bootstrap",
"1.10.5",
"1.10.22",
src = "www/shared/datatables",
package = "shiny",
stylesheet = c("css/dataTables.bootstrap.css", "css/dataTables.extra.css"),
stylesheet = "css/dataTables.bootstrap.css",
script = "js/dataTables.bootstrap.js"
)
)
@@ -1136,12 +1136,49 @@ dataTableDependency <- list(
#' @rdname renderDataTable
#' @export
dataTableOutput <- function(outputId) {
attachDependencies(
div(id = outputId, class="shiny-datatable-output"),
dataTableDependency
)
legacy <- useLegacyDataTable(from = "shiny::dataTableOutput()", to = "DT::DTOutput()")
if (legacy) {
attachDependencies(
div(id = outputId, class = "shiny-datatable-output"),
dataTableDependency
)
} else {
DT::DTOutput(outputId)
}
}
useLegacyDataTable <- function(from, to) {
legacy <- getOption("shiny.legacy.datatable")
# If option has been set, user knows what they're doing
if (!is.null(legacy)) {
return(legacy)
}
# If not set, use DT if a suitable version is available (and inform either way)
hasDT <- is_installed("DT", "0.32.1")
details <- NULL
if (hasDT) {
details <- paste0(c(
"Since you have a suitable version of DT (>= v0.32.1), ",
from,
" will automatically use ",
to,
" under-the-hood.\n",
"If this happens to break your app, set `options(shiny.legacy.datatable = TRUE)` ",
"to get the legacy datatable implementation (or `FALSE` to squelch this message).\n"
), collapse = "")
}
details <- paste0(details, "See <https://rstudio.github.io/DT/shiny.html> for more information.")
shinyDeprecated("1.8.1", from, to, details)
!hasDT
}
#' Create an HTML output element
#'
#' Render a reactive output variable as HTML within an application page. The
@@ -1238,23 +1275,29 @@ downloadButton <- function(outputId,
class=NULL,
...,
icon = shiny::icon("download")) {
aTag <- tags$a(id=outputId,
class=paste('btn btn-default shiny-download-link', class),
href='',
target='_blank',
download=NA,
validateIcon(icon),
label, ...)
tags$a(id=outputId,
class='btn btn-default shiny-download-link disabled',
class=class,
href='',
target='_blank',
download=NA,
"aria-disabled"="true",
tabindex="-1",
validateIcon(icon),
label, ...)
}
#' @rdname downloadButton
#' @export
downloadLink <- function(outputId, label="Download", class=NULL, ...) {
tags$a(id=outputId,
class=paste(c('shiny-download-link', class), collapse=" "),
class='shiny-download-link disabled',
class=class,
href='',
target='_blank',
download=NA,
"aria-disabled"="true",
tabindex="-1",
label, ...)
}

View File

@@ -0,0 +1,13 @@
# Generated by tools/updateSpinners.R: do not edit by hand
.spinner_types <-
c("12-dots-scale-rotate", "180-ring-with-bg", "180-ring", "270-ring-with-bg",
"270-ring", "3-dots-bounce", "3-dots-fade", "3-dots-move", "3-dots-rotate",
"3-dots-scale-middle", "3-dots-scale", "6-dots-rotate", "6-dots-scale-middle",
"6-dots-scale", "8-dots-rotate", "90-ring-with-bg", "90-ring",
"bars-fade", "bars-rotate-fade", "bars-scale-fade", "bars-scale-middle",
"bars-scale", "blocks-scale", "blocks-shuffle-2", "blocks-shuffle-3",
"blocks-wave", "bouncing-ball", "clock", "dot-revolve", "eclipse-half",
"eclipse", "gooey-balls-1", "gooey-balls-2", "pulse-2", "pulse-3",
"pulse-multiple", "pulse-ring", "pulse-rings-2", "pulse-rings-3",
"pulse-rings-multiple", "pulse", "ring-resize", "tadpole", "wifi-fade",
"wifi", "wind-toy")

231
R/busy-indicators.R Normal file
View File

@@ -0,0 +1,231 @@
#' Enable/disable busy indication
#'
#' To enable/disable busy indicators, include the result of this function 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 (for future expansion).
#' @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.
#'
#' To customize the appearance of the busy indicators, include the result of
#' this function in the app's UI.
#'
#' @param ... Currently ignored (for future expansion).
#' @param spinner_type The type of spinner to use for the busy indicator. This
#' can be any of the spinner types from the `shiny` package.
#'
#' Available spinner types include:
#' "`r paste0(.spinner_types, collapse = '", "')`".
#'
#' Alternatively, you can provide a path to a custom spinner SVG file. There
#' are many free spinner SVGs available online, such as those from
#' the [svg-spinners](https://github.com/n3r4zzurr0/svg-spinners) repository.
#' @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 CSS selector for scoping the spinner customization.
#' This can be useful if you want to have different spinners for different
#' parts of the app. Defaults to the root document element. Use `NULL` to
#' return inline styles for spinner customizations (note that you cannot
#' customize both the pulse and the spinner without providing a selector).
#' @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)
#'
#' ui <- page_fillable(
#' useBusyIndicators(),
#' busyIndicatorOptions(spinner_color = "orange"),
#' 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)
busyIndicatorOptions <- function(
...,
spinner_type = NULL,
spinner_color = NULL,
spinner_size = NULL,
spinner_delay = NULL,
spinner_selector = ":root",
pulse_background = NULL,
pulse_height = NULL,
pulse_speed = NULL
) {
rlang::check_dots_empty()
pulse_opts <- pulseOptions(
background = pulse_background,
height = pulse_height,
speed = pulse_speed
)
spinner_opts <- spinnerOptions(
type = spinner_type,
color = spinner_color,
size = spinner_size,
delay = spinner_delay,
selector = spinner_selector
)
if (!is.null(spinner_opts) && is.null(spinner_selector)) {
if (!is.null(pulse_opts)) {
abort(c(
"`spinner_selector` must be provided when customizing both the pulse and the spinner.",
"i" = "`spinner_selector = NULL` returns inline styles for spinner customizations."
))
}
return(spinner_opts)
}
dropNulls(tagList(spinner_opts, pulse_opts))
}
spinnerOptions <- function(
type = NULL,
color = NULL,
size = NULL,
delay = NULL,
selector = ":root"
) {
if (is.null(type) && is.null(color) && is.null(size) && is.null(delay)) {
return(NULL)
}
type_is_file <- file.exists(type) && grepl("\\.svg$", type)
if (!is.null(type)) {
if (type_is_file) {
stopifnot(file.exists(type) && grepl("\\.svg$", type))
typeData <- readBin(type, "raw", n = file.info(type)$size)
type_base64 <- rawToBase64(typeData)
type <- sprintf("url('data:image/svg+xml;base64,%s')", type_base64)
} else {
type <- rlang::arg_match(type, .spinner_types)
type <- sprintf("url('spinners/%s.svg')", type)
}
}
# Options controlled via CSS variables.
css_vars <- htmltools::css(
`--shiny-spinner-url` = type,
`--shiny-spinner-color` = htmltools::parseCssColors(color),
`--shiny-spinner-size` = htmltools::validateCssUnit(size),
`--shiny-spinner-delay` = delay
)
if (is.null(selector)) {
return(css_vars)
}
tags$style(HTML(paste0(selector, " {", css_vars, "}")))
}
pulseOptions <- function(background = NULL, height = NULL, speed = NULL) {
if (is.null(background) && is.null(height) && is.null(speed)) {
return(NULL)
}
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",
script = "busy-indicators.js"
)
}

View File

@@ -42,7 +42,7 @@
#' session to immediately unblock and carry on with other user interactions.
#'
#' @export
ExtendedTask <- R6Class("ExtendedTask", portable = TRUE,
ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE,
public = list(
#' @description
#' Creates a new `ExtendedTask` object. `ExtendedTask` should generally be

View File

@@ -1,31 +1,3 @@
# Check that the version of an suggested package satisfies the requirements
#
# @param package The name of the suggested package
# @param version The version of the package
check_suggested <- function(package, version = NULL) {
if (is_installed(package, version)) {
return()
}
msg <- paste0(
sQuote(package),
if (is.na(version %||% NA)) "" else paste0("(>= ", version, ")"),
" must be installed for this functionality."
)
if (interactive()) {
message(msg, "\nWould you like to install it?")
if (utils::menu(c("Yes", "No")) == 1) {
return(utils::install.packages(package))
}
}
stop(msg, call. = FALSE)
}
# domain is like session
@@ -110,34 +82,15 @@ renderReactlog <- function(sessionToken = NULL, time = TRUE) {
time = time
)
}
check_reactlog <- function() {
check_suggested("reactlog", reactlog_version())
}
# read reactlog version from description file
# prevents version mismatch in code and description file
reactlog_version <- local({
version <- NULL
function() {
if (!is.null(version)) return(version)
desc <- read.dcf(system_file("DESCRIPTION", package = "shiny"))
suggests <- desc[1,"Suggests"][[1]]
suggests_pkgs <- strsplit(suggests, "\n")[[1]]
reactlog_info <- suggests_pkgs[grepl("reactlog", suggests_pkgs)]
if (length(reactlog_info) == 0) {
stop("reactlog can not be found in shiny DESCRIPTION file")
}
reactlog_info <- sub("^[^\\(]*\\(", "", reactlog_info)
reactlog_info <- sub("\\)[^\\)]*$", "", reactlog_info)
reactlog_info <- sub("^[>= ]*", "", reactlog_info)
version <<- package_version(reactlog_info)
version
if (!is_installed("reactlog", reactlog_min_version)) {
rlang::check_installed("reactlog", reactlog_min_version)
}
})
}
# Should match the (suggested) version in DESCRIPTION file
reactlog_min_version <- "1.0.0"
RLog <- R6Class(
"RLog",

View File

@@ -14,7 +14,7 @@ NULL
#' depending on the values in the query string / hash (e.g. instead of basing
#' the conditional on an input or a calculated reactive, you can base it on the
#' query string). However, note that, if you're changing the query string / hash
#' programatically from within the server code, you must use
#' programmatically from within the server code, you must use
#' `updateQueryString(_yourNewQueryString_, mode = "push")`. The default
#' `mode` for `updateQueryString` is `"replace"`, which doesn't
#' raise any events, so any observers or reactives that depend on it will

View File

@@ -48,9 +48,12 @@ Map <- R6Class(
)
)
#' @export
as.list.Map <- function(x, ...) {
x$values()
}
#' @export
length.Map <- function(x) {
x$size()
}

View File

@@ -457,6 +457,11 @@ MockShinySession <- R6Class(
function(v){
list(val = v, err = NULL)
}, catch=function(e){
if (
!inherits(e, c("shiny.custom.error", "shiny.output.cancel", "shiny.output.progress", "shiny.silent.error"))
) {
self$unhandledError(e, close = FALSE)
}
list(val = NULL, err = e)
})
})
@@ -560,10 +565,26 @@ MockShinySession <- R6Class(
rootScope = function() {
self
},
#' @description Add an unhandled error callback.
#' @param callback The callback to add, which should accept an error object
#' as its first argument.
#' @return A deregistration function.
onUnhandledError = function(callback) {
private$unhandledErrorCallbacks$register(callback)
},
#' @description Called by observers when a reactive expression errors.
#' @param e An error object.
unhandledError = function(e) {
self$close()
#' @param close If `TRUE`, the session will be closed after the error is
#' handled, defaults to `FALSE`.
unhandledError = function(e, close = TRUE) {
if (close) {
class(e) <- c("shiny.error.fatal", class(e))
}
private$unhandledErrorCallbacks$invoke(e, onError = printError)
.globals$onUnhandledErrorCallbacks$invoke(e, onError = printError)
if (close) self$close()
},
#' @description Freeze a value until the flush cycle completes.
#' @param x A `ReactiveValues` object.
@@ -620,6 +641,9 @@ MockShinySession <- R6Class(
flushedCBs = NULL,
# @field endedCBs `Callbacks` called when session ends.
endedCBs = NULL,
# @field unhandledErrorCallbacks `Callbacks` called when an unhandled error
# occurs.
unhandledErrorCallbacks = Callbacks$new(),
# @field timer `MockableTimerCallbacks` called at particular times.
timer = NULL,
# @field was_closed Set to `TRUE` once the session is closed.

View File

@@ -1216,7 +1216,7 @@ Observer <- R6Class(
printError(e)
if (!is.null(.domain)) {
.domain$unhandledError(e)
.domain$unhandledError(e, close = TRUE)
}
},
finally = .domain$decrementBusyCount
@@ -2396,7 +2396,7 @@ isNullEvent <- function(value) {
#' reactive recently (within the time window) invalidated. New `r`
#' invalidations do not reset the time window. This means that if invalidations
#' continually come from `r` within the time window, the throttled reactive
#' will invalidate regularly, at a rate equal to or slower than than the time
#' will invalidate regularly, at a rate equal to or slower than the time
#' window.
#'
#' `ooo-oo-oo---- => o--o--o--o---`

View File

@@ -447,6 +447,16 @@ stopApp <- function(returnValue = invisible()) {
#' @param display.mode The mode in which to display the example. Defaults to
#' `showcase`, but may be set to `normal` to see the example without
#' code or commentary.
#' @param package The package in which to find the example (defaults to
#' `"shiny"`).
#'
#' To provide examples in your package, store examples in the
#' `inst/examples-shiny` directory of your package. Each example should be
#' in its own subdirectory and should be runnable when [runApp()] is called
#' on the subdirectory. Example apps can include a `DESCRIPTION` file and a
#' `README.md` file to provide metadata and commentary about the example. See
#' the article on [Display Modes](https://shiny.posit.co/r/articles/build/display-modes/)
#' on the Shiny website for more information.
#' @inheritParams runApp
#'
#' @examples
@@ -462,32 +472,46 @@ stopApp <- function(returnValue = invisible()) {
#' system.file("examples", package="shiny")
#' }
#' @export
runExample <- function(example=NA,
port=getOption("shiny.port"),
launch.browser = getOption('shiny.launch.browser', interactive()),
host=getOption('shiny.host', '127.0.0.1'),
display.mode=c("auto", "normal", "showcase")) {
examplesDir <- system_file('examples', package='shiny')
runExample <- function(
example = NA,
port = getOption("shiny.port"),
launch.browser = getOption("shiny.launch.browser", interactive()),
host = getOption("shiny.host", "127.0.0.1"),
display.mode = c("auto", "normal", "showcase"),
package = "shiny"
) {
if (!identical(package, "shiny") && !is_installed(package)) {
rlang::check_installed(package)
}
use_legacy_shiny_examples <-
identical(package, "shiny") &&
isTRUE(getOption('shiny.legacy.examples', FALSE))
examplesDir <- system_file(
if (use_legacy_shiny_examples) "examples" else "examples-shiny",
package = package
)
dir <- resolve(examplesDir, example)
if (is.null(dir)) {
valid_examples <- sprintf(
'Valid examples in {%s}: "%s"',
package,
paste(list.files(examplesDir), collapse = '", "')
)
if (is.na(example)) {
errFun <- message
errMsg <- ''
}
else {
errFun <- stop
errMsg <- paste('Example', example, 'does not exist. ')
message(valid_examples)
return(invisible())
}
errFun(errMsg,
'Valid examples are "',
paste(list.files(examplesDir), collapse='", "'),
'"')
}
else {
runApp(dir, port = port, host = host, launch.browser = launch.browser,
display.mode = display.mode)
stop("Example '", example, "' does not exist. ", valid_examples)
}
runApp(dir, port = port, host = host, launch.browser = launch.browser,
display.mode = display.mode)
}
#' Run a gadget

View File

@@ -113,7 +113,7 @@ getShinyOption <- function(name, default = NULL) {
#' production.}
#' \item{shiny.sanitize.errors (defaults to `FALSE`)}{If `TRUE`, then normal errors (i.e.
#' errors not wrapped in `safeError`) won't show up in the app; a simple
#' generic error message is printed instead (the error and strack trace printed
#' generic error message is printed instead (the error and stack trace printed
#' to the console remain unchanged). If you want to sanitize errors in general, but you DO want a
#' particular error `e` to get displayed to the user, then set this option
#' to `TRUE` and use `stop(safeError(e))` for errors you want the

View File

@@ -1,7 +1,6 @@
# See also R/reexports.R
## usethis namespace: start
## usethis namespace: end
#' @importFrom lifecycle deprecated is_present
#' @importFrom grDevices dev.set dev.cur
#' @importFrom fastmap fastmap
@@ -18,13 +17,13 @@
#' is_false list2
#' missing_arg is_missing maybe_missing
#' quo_is_missing fn_fmls<- fn_body fn_body<-
#' @importFrom ellipsis
#' check_dots_empty check_dots_unnamed
#' @import htmltools
#' @import httpuv
#' @import xtable
#' @import R6
#' @import mime
## usethis namespace: end
NULL
# It's necessary to Depend on methods so Rscript doesn't fail. It's necessary

120
R/shiny.R
View File

@@ -16,8 +16,7 @@ NULL
#'
#' @name shiny-package
#' @aliases shiny
#' @docType package
NULL
"_PACKAGE"
createUniqueId <- function(bytes, prefix = "", suffix = "") {
withPrivateSeed({
@@ -215,7 +214,7 @@ workerId <- local({
#' Sends a custom message to the web page. `type` must be a
#' single-element character vector giving the type of message, while
#' `message` can be any jsonlite-encodable value. Custom messages
#' have no meaning to Shiny itself; they are used soley to convey information
#' have no meaning to Shiny itself; they are used solely to convey information
#' to custom JavaScript logic in the browser. You can do this by adding
#' JavaScript code to the browser that calls
#' \code{Shiny.addCustomMessageHandler(type, function(message){...})}
@@ -363,6 +362,7 @@ ShinySession <- R6Class(
flushCallbacks = 'Callbacks',
flushedCallbacks = 'Callbacks',
inputReceivedCallbacks = 'Callbacks',
unhandledErrorCallbacks = 'Callbacks',
bookmarkCallbacks = 'Callbacks',
bookmarkedCallbacks = 'Callbacks',
restoreCallbacks = 'Callbacks',
@@ -724,6 +724,7 @@ ShinySession <- R6Class(
private$flushCallbacks <- Callbacks$new()
private$flushedCallbacks <- Callbacks$new()
private$inputReceivedCallbacks <- Callbacks$new()
private$unhandledErrorCallbacks <- Callbacks$new()
private$.input <- ReactiveValues$new(dedupe = FALSE, label = "input")
private$.clientData <- ReactiveValues$new(dedupe = TRUE, label = "clientData")
private$timingRecorder <- ShinyServerTimingRecorder$new()
@@ -1044,8 +1045,21 @@ ShinySession <- R6Class(
new data from the client."
return(private$inputReceivedCallbacks$register(callback))
},
unhandledError = function(e) {
self$close()
onUnhandledError = function(callback) {
"Registers the callback to be invoked when an unhandled error occurs."
return(private$unhandledErrorCallbacks$register(callback))
},
unhandledError = function(e, close = TRUE) {
"Call the global and session unhandled error handlers and then close the
session if the error is fatal."
if (close) {
class(e) <- c("shiny.error.fatal", class(e))
}
private$unhandledErrorCallbacks$invoke(e, onError = printError)
.globals$onUnhandledErrorCallbacks$invoke(e, onError = printError)
if (close) self$close()
},
close = function() {
if (!self$closed) {
@@ -1169,6 +1183,7 @@ ShinySession <- R6Class(
"logs or contact the app author for",
"clarification."))
}
self$unhandledError(cond, close = FALSE)
invisible(structure(list(), class = "try-error", condition = cond))
}
}
@@ -2370,23 +2385,89 @@ getCurrentOutputInfo <- function(session = getDefaultReactiveDomain()) {
#' Add callbacks for Shiny session events
#'
#' @description
#' These functions are for registering callbacks on Shiny session events.
#' `onFlush` registers a function that will be called before Shiny flushes
#' the reactive system. `onFlushed` registers a function that will be
#' called after Shiny flushes the reactive system. `onSessionEnded`
#' registers a function to be called after the client has disconnected.
#' `onFlush` registers a function that will be called before Shiny flushes the
#' reactive system. `onFlushed` registers a function that will be called after
#' Shiny flushes the reactive system. `onUnhandledError` registers a function to
#' be called when an unhandled error occurs before the session is closed.
#' `onSessionEnded` registers a function to be called after the client has
#' disconnected.
#'
#' These functions should be called within the application's server function.
#'
#' All of these functions return a function which can be called with no
#' arguments to cancel the registration.
#'
#' @section Unhandled Errors:
#' Unhandled errors are errors that aren't otherwise handled by Shiny or by the
#' application logic. In other words, they are errors that will either cause the
#' application to crash or will result in "Error" output in the UI.
#'
#' You can use `onUnhandledError()` to register a function that will be called
#' when an unhandled error occurs. This function will be called with the error
#' object as its first argument. If the error is fatal and will result in the
#' session closing, the error condition will have the `shiny.error.fatal` class.
#'
#' Note that the `onUnhandledError()` callbacks cannot be used to prevent the
#' app from closing or to modify the error condition. Instead, they are intended
#' to give you an opportunity to log the error or perform other cleanup
#' operations.
#'
#' @param fun A callback function.
#' @param once Should the function be run once, and then cleared, or should it
#' re-run each time the event occurs. (Only for `onFlush` and
#' `onFlushed`.)
#' @param session A shiny session object.
#'
#' @examplesIf interactive()
#' library(shiny)
#'
#' ui <- fixedPage(
#' markdown(c(
#' "Set the number to 8 or higher to cause an error",
#' "in the `renderText()` output."
#' )),
#' sliderInput("number", "Number", 0, 10, 4),
#' textOutput("text"),
#' hr(),
#' markdown(c(
#' "Click the button below to crash the app with an unhandled error",
#' "in an `observe()` block."
#' )),
#' actionButton("crash", "Crash the app!")
#' )
#'
#' log_event <- function(level, ...) {
#' ts <- strftime(Sys.time(), " [%F %T] ")
#' message(level, ts, ...)
#' }
#'
#' server <- function(input, output, session) {
#' log_event("INFO", "Session started")
#'
#' onUnhandledError(function(err) {
#' # log the unhandled error
#' level <- if (inherits(err, "shiny.error.fatal")) "FATAL" else "ERROR"
#' log_event(level, conditionMessage(err))
#' })
#'
#' onStop(function() {
#' log_event("INFO", "Session ended")
#' })
#'
#' observeEvent(input$crash, stop("Oops, an unhandled error happened!"))
#'
#' output$text <- renderText({
#' if (input$number > 7) {
#' stop("that's too high!")
#' }
#' sprintf("You picked number %d.", input$number)
#' })
#' }
#'
#' shinyApp(ui, server)
#'
#' @export
onFlush <- function(fun, once = TRUE, session = getDefaultReactiveDomain()) {
session$onFlush(fun, once = once)
@@ -2407,6 +2488,27 @@ onSessionEnded <- function(fun, session = getDefaultReactiveDomain()) {
session$onSessionEnded(fun)
}
.globals$onUnhandledErrorCallbacks <- NULL
on_load({
.globals$onUnhandledErrorCallbacks <- Callbacks$new()
})
#' @rdname onFlush
#' @export
onUnhandledError <- function(fun, session = getDefaultReactiveDomain()) {
if (!is.function(fun) || length(formals(fun)) == 0) {
rlang::abort(
"The unhandled error callback must be a function that takes an error object as its first argument."
)
}
if (is.null(session)) {
.globals$onUnhandledErrorCallbacks$register(fun)
} else {
session$onUnhandledError(fun)
}
}
flushPendingSessions <- function() {
lapply(appsNeedingFlush$values(), function(shinysession) {

View File

@@ -351,17 +351,6 @@ loadSupport <- function(appDir=NULL, renv=new.env(parent=globalenv()), globalren
appDir <- findEnclosingApp(".")
}
descFile <- file.path.ci(appDir, "DESCRIPTION")
if (file.exists(file.path.ci(appDir, "NAMESPACE")) ||
(file.exists(descFile) &&
identical(as.character(read.dcf(descFile, fields = "Type")), "Package")))
{
warning(
"Loading R/ subdirectory for Shiny application, but this directory appears ",
"to contain an R package. Sourcing files in R/ may cause unexpected behavior."
)
}
if (!is.null(globalrenv)){
# Evaluate global.R, if it exists.
globalPath <- file.path.ci(appDir, "global.R")
@@ -376,10 +365,12 @@ loadSupport <- function(appDir=NULL, renv=new.env(parent=globalenv()), globalren
helpersDir <- file.path(appDir, "R")
disabled <- list.files(helpersDir, pattern="^_disable_autoload\\.r$", recursive=FALSE, ignore.case=TRUE)
if (length(disabled) > 0){
if (length(disabled) > 0) {
return(invisible(renv))
}
warn_if_app_dir_is_package(appDir)
helpers <- list.files(helpersDir, pattern="\\.[rR]$", recursive=FALSE, full.names=TRUE)
# Ensure files in R/ are sorted according to the 'C' locale before sourcing.
# This convention is based on the default for packages. For details, see:
@@ -394,6 +385,27 @@ loadSupport <- function(appDir=NULL, renv=new.env(parent=globalenv()), globalren
invisible(renv)
}
warn_if_app_dir_is_package <- function(appDir) {
has_namespace <- file.exists(file.path.ci(appDir, "NAMESPACE"))
has_desc_pkg <- FALSE
if (!has_namespace) {
descFile <- file.path.ci(appDir, "DESCRIPTION")
has_desc_pkg <-
file.exists(descFile) &&
identical(as.character(read.dcf(descFile, fields = "Type")), "Package")
}
if (has_namespace || has_desc_pkg) {
warning(
"Loading R/ subdirectory for Shiny application, but this directory appears ",
"to contain an R package. Sourcing files in R/ may cause unexpected behavior. ",
"See `?loadSupport` for more details."
)
}
}
# This reads in an app dir for a single-file application (e.g. app.R), and
# returns a shiny.appobj.
# appDir must be a normalized (absolute) path, not a relative one

View File

@@ -69,6 +69,21 @@ renderPage <- function(ui, showcase=0, testMode=FALSE) {
)
}
if (in_devmode()) {
# If we're in dev mode, add a simple script to the head that injects a
# global variable for the client to use to detect dev mode.
shiny_deps[[length(shiny_deps) + 1]] <-
htmlDependency(
"shiny-devmode",
get_package_version("shiny"),
src = "www/shared",
package = "shiny",
head="<script>window.__SHINY_DEV_MODE__ = true;</script>",
all_files = FALSE
)
}
html <- renderDocument(ui, shiny_deps, processDep = createWebDependency)
enc2utf8(paste(collapse = "\n", html))
}
@@ -99,6 +114,7 @@ jqueryDependency <- function() {
shinyDependencies <- function() {
list(
bslib::bs_dependency_defer(shinyDependencyCSS),
busyIndicatorDependency(),
htmlDependency(
name = "shiny-javascript",
version = get_package_version("shiny"),
@@ -159,7 +175,7 @@ shinyDependencyCSS <- function(theme) {
#' This function is kept for backwards compatibility with older applications. It
#' returns the value that is passed to it.
#'
#' @param ui A user interace definition
#' @param ui A user interface definition
#' @return The user interface definition, without modifications or side effects.
#' @keywords internal
#' @export

View File

@@ -778,8 +778,8 @@ renderUI <- function(expr, env = parent.frame(), quoted = FALSE,
#' function.)
#' @param contentType A string of the download's
#' [content type](https://en.wikipedia.org/wiki/Internet_media_type), for
#' example `"text/csv"` or `"image/png"`. If `NULL`, the content type
#' will be guessed based on the filename extension, or
#' example `"text/csv"` or `"image/png"`. If `NULL`, the content type
#' will be guessed based on the filename extension, or
#' `application/octet-stream` if the extension is unknown.
#' @param outputArgs A list of arguments to be passed through to the implicit
#' call to [downloadButton()] when `downloadHandler` is used
@@ -822,20 +822,12 @@ downloadHandler <- function(filename, content, contentType=NULL, outputArgs=list
#' Table output with the JavaScript DataTables library
#'
#' @description
#' `r lifecycle::badge("superseded")` Please use
#' \href{https://rstudio.github.io/DT/shiny.html}{\code{DT::renderDataTable()}}.
#' (Shiny 0.11.1)
#' `r lifecycle::badge("deprecated")`
#'
#' Makes a reactive version of the given function that returns a data frame (or
#' matrix), which will be rendered with the [DataTables](https://datatables.net)
#' library. Paging, searching, filtering, and sorting can be done on the R side
#' using Shiny as the server infrastructure.
#'
#' This function only provides the server-side version of DataTables (using R
#' to process the data object on the server side). There is a separate
#' [DT](https://github.com/rstudio/DT) that allows you to create both
#' server-side and client-side DataTables, and supports additional features.
#' Learn more at <https://rstudio.github.io/DT/shiny.html>.
#' This function is deprecated, use
#' [DT::renderDT()](https://rstudio.github.io/DT/shiny.html) instead. It
#' provides a superset of functionality, better performance, and better user
#' experience.
#'
#' @param expr An expression that returns a data frame or a matrix.
#' @inheritParams renderTable
@@ -887,18 +879,60 @@ downloadHandler <- function(filename, content, contentType=NULL, outputArgs=list
#' }
#' )
#' }
#' @keywords internal
renderDataTable <- function(expr, options = NULL, searchDelay = 500,
callback = 'function(oTable) {}', escape = TRUE,
env = parent.frame(), quoted = FALSE,
outputArgs=list())
{
outputArgs = list()) {
if (in_devmode()) {
shinyDeprecated(
"0.11.1", "shiny::renderDataTable()", "DT::renderDataTable()",
details = "See <https://rstudio.github.io/DT/shiny.html> for more information"
legacy <- useLegacyDataTable(
from = "shiny::renderDataTable()",
to = "DT::renderDT()"
)
if (!quoted) {
expr <- substitute(expr)
quoted <- TRUE
}
if (legacy) {
legacyRenderDataTable(
expr, env = env, quoted = quoted,
options = options,
searchDelay = searchDelay,
callback = callback,
escape = escape,
outputArgs = outputArgs
)
} else {
if (!missing(searchDelay)) {
warning("Ignoring renderDataTable()'s searchDelay value (since DT::renderDT() has no equivalent).")
}
force(options)
force(callback)
force(escape)
force(outputArgs)
DT::renderDataTable(
expr, env = env, quoted = quoted,
options = if (is.null(options)) list() else options,
# Turn function into a statement
callback = DT::JS(paste0("(", callback, ")(table)")),
escape = escape,
outputArgs = outputArgs
)
}
}
legacyRenderDataTable <- function(expr, options = NULL, searchDelay = 500,
callback = 'function(oTable) {}', escape = TRUE,
env = parent.frame(), quoted = FALSE,
outputArgs=list()) {
func <- installExprFunction(expr, "func", env, quoted, label = "renderDataTable")

View File

@@ -150,13 +150,13 @@ updateCheckboxInput <- function(session = getDefaultReactiveDomain(), inputId, l
#' label = "New label",
#' icon = icon("calendar"))
#'
#' # Leaves goButton2's label unchaged and
#' # Leaves goButton2's label unchanged and
#' # removes its icon
#' updateActionButton(session, "goButton2",
#' icon = character(0))
#'
#' # Leaves goButton3's icon, if it exists,
#' # unchaged and changes its label
#' # unchanged and changes its label
#' updateActionButton(session, "goButton3",
#' label = "New label 3")
#'

View File

@@ -493,7 +493,6 @@ shinyCallingHandlers <- function(expr) {
)
}
#' Register a function with the debugger (if one is active).
#'
#' Call this function after exprToFunction to give any active debugger a hook
@@ -1093,7 +1092,7 @@ need <- function(expr, message = paste(label, "must be provided"), label) {
#'
#' You can use `req(FALSE)` (i.e. no condition) if you've already performed
#' all the checks you needed to by that point and just want to stop the reactive
#' chain now. There is no advantange to this, except perhaps ease of readibility
#' chain now. There is no advantage to this, except perhaps ease of readability
#' if you have a complicated condition to check for (or perhaps if you'd like to
#' divide your condition into nested `if` statements).
#'

View File

@@ -3,7 +3,7 @@
<!-- badges: start -->
[![CRAN](https://www.r-pkg.org/badges/version/shiny)](https://CRAN.R-project.org/package=shiny)
[![R build status](https://github.com/rstudio/shiny/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/rstudio/shiny/actions)
[![RStudio community](https://img.shields.io/badge/community-shiny-blue?style=social&logo=rstudio&logoColor=75AADB)](https://community.rstudio.com/new-topic?category=shiny&tags=shiny)
[![RStudio community](https://img.shields.io/badge/community-shiny-blue?style=social&logo=rstudio&logoColor=75AADB)](https://forum.posit.co/new-topic?category=shiny&tags=shiny)
<!-- badges: end -->
@@ -51,7 +51,7 @@ If you want to chat about Shiny, meet other developers, or help us decide what t
## Getting Help
To ask a question about Shiny, please use the [RStudio Community website](https://community.rstudio.com/new-topic?category=shiny&tags=shiny).
To ask a question about Shiny, please use the [RStudio Community website](https://forum.posit.co/new-topic?category=shiny&tags=shiny).
For bug reports, please use the [issue tracker](https://github.com/rstudio/shiny/issues) and also keep in mind that by [writing a good bug report](https://github.com/rstudio/shiny/wiki/Writing-Good-Bug-Reports), you're more likely to get help with your problem.

View File

@@ -0,0 +1,154 @@
<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

After

Width:  |  Height:  |  Size: 312 KiB

View File

@@ -0,0 +1,6 @@
Title: Hello Shiny!
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,3 @@
This small Shiny application demonstrates Shiny's automatic UI updates.
Move the *Number of bins* slider and notice how the `renderPlot` expression is automatically re-evaluated when its dependant, `input$bins`, changes, causing a histogram with a new number of bins to be rendered.

View File

@@ -0,0 +1,54 @@
library(shiny)
library(bslib)
# Define UI for app that draws a histogram ----
ui <- page_sidebar(
# App title ----
title = "Hello Shiny!",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Slider for the number of bins ----
sliderInput(
inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30
)
),
# Output: Histogram ----
plotOutput(outputId = "distPlot")
)
# Define server logic required to draw a histogram ----
server <- function(input, output) {
# Histogram of the Old Faithful Geyser Data ----
# with requested number of bins
# This expression that generates a histogram is wrapped in a call
# to renderPlot to indicate that:
#
# 1. It is "reactive" and therefore should be automatically
# re-executed when inputs (input$bins) change
# 2. Its output type is a plot
output$distPlot <- renderPlot({
x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(
x,
breaks = bins,
col = "#75AADB",
border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times"
)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)

View File

@@ -0,0 +1,6 @@
Title: Shiny Text
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1 @@
This example demonstrates output of raw text from R using the `renderPrint` function in `server` and the `verbatimTextOutput` function in `ui`. In this case, a textual summary of the data is shown using R's built-in `summary` function.

View File

@@ -0,0 +1,61 @@
library(shiny)
library(bslib)
# Define UI for dataset viewer app ----
ui <- page_sidebar(
# App title ----
title = "Shiny Text",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Selector for choosing dataset ----
selectInput(
inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")
),
# Input: Numeric entry for number of obs to view ----
numericInput(
inputId = "obs",
label = "Number of observations to view:",
value = 10
)
),
# Output: Verbatim text for data summary ----
verbatimTextOutput("summary"),
# Output: HTML table with requested number of observations ----
tableOutput("view")
)
# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {
# Return the requested dataset ----
datasetInput <- reactive({
switch(
input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars
)
})
# Generate a summary of the dataset ----
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# Show the first "n" observations ----
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)

View File

@@ -0,0 +1,6 @@
Title: Reactivity
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,5 @@
This example demonstrates a core feature of Shiny: **reactivity**. In the `server` function, a reactive called `datasetInput` is declared.
Notice that the reactive expression depends on the input expression `input$dataset`, and that it's used by two output expressions: `output$summary` and `output$view`. Try changing the dataset (using *Choose a dataset*) while looking at the reactive and then at the outputs; you will see first the reactive and then its dependencies flash.
Notice also that the reactive expression doesn't just update whenever anything changes--only the inputs it depends on will trigger an update. Change the "Caption" field and notice how only the `output$caption` expression is re-evaluated; the reactive and its dependents are left alone.

View File

@@ -0,0 +1,100 @@
library(shiny)
library(bslib)
# Define UI for dataset viewer app ----
ui <- page_sidebar(
# App title ----
title = "Reactivity",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Text for providing a caption ----
# Note: Changes made to the caption in the textInput control
# are updated in the output area immediately as you type
textInput(
inputId = "caption",
label = "Caption:",
value = "Data Summary"
),
# Input: Selector for choosing dataset ----
selectInput(
inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")
),
# Input: Numeric entry for number of obs to view ----
numericInput(
inputId = "obs",
label = "Number of observations to view:",
value = 10
)
),
# Output: Formatted text for caption ----
h3(textOutput("caption", container = span)),
# Output: Verbatim text for data summary ----
verbatimTextOutput("summary"),
# Output: HTML table with requested number of observations ----
tableOutput("view")
)
# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {
# Return the requested dataset ----
# By declaring datasetInput as a reactive expression we ensure
# that:
#
# 1. It is only called when the inputs it depends on changes
# 2. The computation and result are shared by all the callers,
# i.e. it only executes a single time
datasetInput <- reactive({
switch(
input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars
)
})
# Create caption ----
# The output$caption is computed based on a reactive expression
# that returns input$caption. When the user changes the
# "caption" field:
#
# 1. This function is automatically called to recompute the output
# 2. New caption is pushed back to the browser for re-display
#
# Note that because the data-oriented reactive expressions
# below don't depend on input$caption, those expressions are
# NOT called when input$caption changes
output$caption <- renderText({
input$caption
})
# Generate a summary of the dataset ----
# The output$summary depends on the datasetInput reactive
# expression, so will be re-executed whenever datasetInput is
# invalidated, i.e. whenever the input$dataset changes
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# Show the first "n" observations ----
# The output$view depends on both the databaseInput reactive
# expression and input$obs, so it will be re-executed whenever
# input$dataset or input$obs is changed
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: Miles Per Gallon
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,4 @@
This example demonstrates the following concepts:
- **Global variables**: The `mpgData` variable is declared outside of the `ui` and `server` function definitions. This makes it available anywhere inside `app.R`. The code in `app.R` outside of `ui` and `server` function definitions is only run once when the app starts up, so it can't contain user input.
- **Reactive expressions**: `formulaText` is a reactive expression. Note how it re-evaluates when the Variable field is changed, but not when the Show Outliers box is unchecked.

View File

@@ -0,0 +1,73 @@
library(shiny)
library(bslib)
library(datasets)
# Data pre-processing ----
# Tweak the "am" variable to have nicer factor labels -- since this
# doesn't rely on any user inputs, we can do this once at startup
# and then use the value throughout the lifetime of the app
mpgData <- mtcars
mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))
# Define UI for miles per gallon app ----
ui <- page_sidebar(
# App title ----
title = "Miles Per Gallon",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Selector for variable to plot against mpg ----
selectInput(
"variable",
"Variable:",
c(
"Cylinders" = "cyl",
"Transmission" = "am",
"Gears" = "gear"
)
),
# Input: Checkbox for whether outliers should be included ----
checkboxInput("outliers", "Show outliers", TRUE)
),
# Output: Formatted text for caption ----
h3(textOutput("caption")),
# Output: Plot of the requested variable against mpg ----
plotOutput("mpgPlot")
)
# Define server logic to plot various variables against mpg ----
server <- function(input, output) {
# Compute the formula text ----
# This is in a reactive expression since it is shared by the
# output$caption and output$mpgPlot functions
formulaText <- reactive({
paste("mpg ~", input$variable)
})
# Return the formula text for printing as a caption ----
output$caption <- renderText({
formulaText()
})
# Generate a plot of the requested variable against mpg ----
# and only exclude outliers if requested
output$mpgPlot <- renderPlot({
boxplot(
as.formula(formulaText()),
data = mpgData,
outline = input$outliers,
col = "#75AADB",
pch = 19
)
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: Sliders
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,3 @@
This example demonstrates Shiny's versatile `sliderInput` widget.
Slider inputs can be used to select single values, to select a continuous range of values, and even to animate over a range.

View File

@@ -0,0 +1,103 @@
library(shiny)
library(bslib)
# Define UI for slider demo app ----
ui <- page_sidebar(
# App title ----
title = "Sliders",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Simple integer interval ----
sliderInput(
"integer",
"Integer:",
min = 0,
max = 1000,
value = 500
),
# Input: Decimal interval with step value ----
sliderInput(
"decimal",
"Decimal:",
min = 0,
max = 1,
value = 0.5,
step = 0.1
),
# Input: Specification of range within an interval ----
sliderInput(
"range",
"Range:",
min = 1,
max = 1000,
value = c(200, 500)
),
# Input: Custom currency format for with basic animation ----
sliderInput(
"format",
"Custom Format:",
min = 0,
max = 10000,
value = 0,
step = 2500,
pre = "$",
sep = ",",
animate = TRUE
),
# Input: Animation with custom interval (in ms) ----
# to control speed, plus looping
sliderInput(
"animation",
"Looping Animation:",
min = 1,
max = 2000,
value = 1,
step = 10,
animate =
animationOptions(interval = 300, loop = TRUE)
)
),
# Output: Table summarizing the values entered ----
tableOutput("values")
)
# Define server logic for slider examples ----
server <- function(input, output) {
# Reactive expression to create data frame of all input values ----
sliderValues <- reactive({
data.frame(
Name = c(
"Integer",
"Decimal",
"Range",
"Custom Format",
"Animation"
),
Value = as.character(c(
input$integer,
input$decimal,
paste(input$range, collapse = " "),
input$format,
input$animation
)),
stringsAsFactors = FALSE
)
})
# Show the values in an HTML table ----
output$values <- renderTable({
sliderValues()
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: Tabsets
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,9 @@
This example demonstrates the `navset_*` and `nav_panel` widgets from the `bslib` package.
Notice that outputs that are not visible are not re-evaluated until they become visible. Try this:
1. Scroll to the bottom of the `server` function. You might need to use the *show with app* option so you can easily view the code and interact with the app at the same time.
2. Change the number of observations, and observe that only `output$plot` is evaluated.
3. Click the Summary tab, and observe that `output$summary` is evaluated.
4. Change the number of observations again, and observe that now only `output$summary` is evaluated.

View File

@@ -0,0 +1,99 @@
library(shiny)
library(bslib)
# Define UI for random distribution app ----
# Sidebar layout with input and output definitions ----
ui <- page_sidebar(
# App title ----
title = "Tabsets",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Select the random distribution type ----
radioButtons(
"dist",
"Distribution type:",
c(
"Normal" = "norm",
"Uniform" = "unif",
"Log-normal" = "lnorm",
"Exponential" = "exp"
)
),
# br() element to introduce extra vertical spacing ----
br(),
# Input: Slider for the number of observations to generate ----
sliderInput(
"n",
"Number of observations:",
value = 500,
min = 1,
max = 1000
)
),
# Main panel for displaying outputs ----
# Output: A tabset that combines three panels ----
navset_card_underline(
# Panel with plot ----
nav_panel("Plot", plotOutput("plot")),
# Panel with summary ----
nav_panel("Summary", verbatimTextOutput("summary")),
# Panel with table ----
nav_panel("Table", tableOutput("table"))
)
)
# Define server logic for random distribution app ----
server <- function(input, output) {
# Reactive expression to generate the requested distribution ----
# This is called whenever the inputs change. The output functions
# defined below then use the value computed from this expression
d <- reactive({
dist <- switch(
input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm
)
dist(input$n)
})
# Generate a plot of the data ----
# Also uses the inputs to build the plot label. Note that the
# dependencies on the inputs and the data reactive expression are
# both tracked, and all expressions are called in the sequence
# implied by the dependency graph.
output$plot <- renderPlot({
dist <- input$dist
n <- input$n
hist(
d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB",
border = "white"
)
})
# Generate a summary of the data ----
output$summary <- renderPrint({
summary(d())
})
# Generate an HTML table view of the data ----
output$table <- renderTable({
d()
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: Widgets
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1 @@
This example demonstrates some additional widgets included in Shiny, such as `helpText` and `actionButton`. The latter is used to delay rendering output until the user explicitly requests it (a construct which also introduces two important server functions, `eventReactive` and `isolate`).

View File

@@ -0,0 +1,83 @@
library(shiny)
library(bslib)
# Define UI for slider demo app ----
ui <- page_sidebar(
# App title ----
title = "More Widgets",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Select a dataset ----
selectInput(
"dataset",
"Choose a dataset:",
choices = c("rock", "pressure", "cars")
),
# Input: Specify the number of observations to view ----
numericInput("obs", "Number of observations to view:", 10),
# Include clarifying text ----
helpText(
"Note: while the data view will show only the specified",
"number of observations, the summary will still be based",
"on the full dataset."
),
# Input: actionButton() to defer the rendering of output ----
# until the user explicitly clicks the button (rather than
# doing it immediately when inputs change). This is useful if
# the computations required to render output are inordinately
# time-consuming.
actionButton("update", "Update View")
),
# Output: Header + summary of distribution ----
h4("Summary"),
verbatimTextOutput("summary"),
# Output: Header + table of distribution ----
h4("Observations"),
tableOutput("view")
)
# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {
# Return the requested dataset ----
# Note that we use eventReactive() here, which depends on
# input$update (the action button), so that the output is only
# updated when the user clicks the button
datasetInput <- eventReactive(
input$update,
{
switch(
input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars
)
},
ignoreNULL = FALSE
)
# Generate a summary of the dataset ----
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})
# Show the first "n" observations ----
# The use of isolate() is necessary because we don't want the table
# to update whenever input$obs changes (only when the user clicks
# the action button)
output$view <- renderTable({
head(datasetInput(), n = isolate(input$obs))
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -2,6 +2,5 @@ Title: Custom HTML UI
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

View File

@@ -7,12 +7,14 @@ server <- function(input, output) {
# This is called whenever the inputs change. The output functions
# defined below then use the value computed from this expression
d <- reactive({
dist <- switch(input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm)
dist <- switch(
input$dist,
norm = rnorm,
unif = runif,
lnorm = rlnorm,
exp = rexp,
rnorm
)
dist(input$n)
})
@@ -26,9 +28,12 @@ server <- function(input, output) {
dist <- input$dist
n <- input$n
hist(d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB", border = "white")
hist(
d(),
main = paste("r", dist, "(", n, ")", sep = ""),
col = "#75AADB",
border = "white"
)
})
# Generate a summary of the data ----
@@ -40,7 +45,6 @@ server <- function(input, output) {
output$table <- renderTable({
head(data.frame(x = d()))
})
}
# Create Shiny app ----

View File

@@ -0,0 +1,6 @@
Title: File Upload
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,3 @@
We can add a file upload input in the UI using the function `fileInput()`,
e.g. `fileInput('foo')`. In the `server` function, we can access the
uploaded files via `input$foo`.

View File

@@ -0,0 +1,99 @@
library(shiny)
library(bslib)
# Define UI for slider demo app ----
ui <- page_sidebar(
# App title ----
title = "Uploading Files",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Select a file ----
fileInput(
"file1",
"Choose CSV File",
multiple = TRUE,
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
# Horizontal line ----
tags$hr(),
# Input: Checkbox if file has header ----
checkboxInput("header", "Header", TRUE),
# Input: Select separator ----
radioButtons(
"sep",
"Separator",
choices = c(
Comma = ",",
Semicolon = ";",
Tab = "\t"
),
selected = ","
),
# Input: Select quotes ----
radioButtons(
"quote",
"Quote",
choices = c(
None = "",
"Double Quote" = '"',
"Single Quote" = "'"
),
selected = '"'
),
# Horizontal line ----
tags$hr(),
# Input: Select number of rows to display ----
radioButtons(
"disp",
"Display",
choices = c(
Head = "head",
All = "all"
),
selected = "head"
)
),
# Output: Data file ----
tableOutput("contents")
)
# Define server logic to read selected file ----
server <- function(input, output) {
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, head of that data file by default,
# or all rows if selected, will be shown.
req(input$file1)
df <- read.csv(
input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote
)
if (input$disp == "head") {
return(head(df))
} else {
return(df)
}
})
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: File Download
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,2 @@
We can add a download button to the UI using `downloadButton()`, and write
the content of the file in `downloadHandler()` in the `server` function.

View File

@@ -0,0 +1,56 @@
library(shiny)
library(bslib)
# Define UI for slider demo app ----
ui <- page_sidebar(
# App title ----
title = "Downloading Data",
# Sidebar panel for inputs ----
sidebar = sidebar(
# Input: Choose dataset ----
selectInput(
"dataset",
"Choose a dataset:",
choices = c("rock", "pressure", "cars")
),
# Button
downloadButton("downloadData", "Download")
),
tableOutput("table")
)
# Define server logic to display and download selected file ----
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(
input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars
)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
)
}
# Create Shiny app ----
shinyApp(ui, server)

View File

@@ -0,0 +1,6 @@
Title: Timer
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
Tags: getting-started
Type: Shiny

View File

@@ -0,0 +1,4 @@
The function `invalidateLater()` can be used to invalidate an observer or
reactive expression in a given number of milliseconds. In this example, the
output `currentTime` is updated every second, so it shows the current time
on a second basis.

View File

@@ -0,0 +1,18 @@
library(shiny)
library(bslib)
# Define UI for displaying current time ----
ui <- page_fluid(
h2(textOutput("currentTime"))
)
# Define server logic to show current time, update every second ----
server <- function(input, output, session) {
output$currentTime <- renderText({
invalidateLater(1000, session)
paste("The current time is", Sys.time())
})
}
# Create Shiny app ----
shinyApp(ui, server)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
/*! shiny 1.8.1.9001 | (c) 2012-2024 RStudio, PBC. | License: GPL-3 | file LICENSE */
"use strict";(function(){document.documentElement.classList.add("shiny-not-yet-idle");$(document).one("shiny:idle",function(){document.documentElement.classList.remove("shiny-not-yet-idle")});})();
//# sourceMappingURL=busy-indicators.js.map

View File

@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../../srcts/extras/busy-indicators/busy-indicators.ts"],
"sourcesContent": ["// Think of this like the .shiny-busy class that shiny.js puts on the root element,\n// except it's added before shiny.js is initialized, connected, etc.\ndocument.documentElement.classList.add(\"shiny-not-yet-idle\");\n$(document).one(\"shiny:idle\", function () {\n document.documentElement.classList.remove(\"shiny-not-yet-idle\");\n});"],
"mappings": ";yBAEA,SAAS,gBAAgB,UAAU,IAAI,oBAAoB,EAC3D,EAAE,QAAQ,EAAE,IAAI,aAAc,UAAY,CACxC,SAAS,gBAAgB,UAAU,OAAO,oBAAoB,CAChE,CAAC",
"names": []
}

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><circle cx="12" cy="3" r="1"><animate id="spinner_7Z73" begin="0;spinner_tKsu.end-0.5s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="16.50" cy="4.21" r="1"><animate id="spinner_Wd87" begin="spinner_7Z73.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="7.50" cy="4.21" r="1"><animate id="spinner_tKsu" begin="spinner_9Qlc.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="19.79" cy="7.50" r="1"><animate id="spinner_lMMO" begin="spinner_Wd87.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="4.21" cy="7.50" r="1"><animate id="spinner_9Qlc" begin="spinner_Khxv.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="21.00" cy="12.00" r="1"><animate id="spinner_5L9t" begin="spinner_lMMO.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="3.00" cy="12.00" r="1"><animate id="spinner_Khxv" begin="spinner_ld6P.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="19.79" cy="16.50" r="1"><animate id="spinner_BfTD" begin="spinner_5L9t.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="4.21" cy="16.50" r="1"><animate id="spinner_ld6P" begin="spinner_XyBs.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="16.50" cy="19.79" r="1"><animate id="spinner_7gAK" begin="spinner_BfTD.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="7.50" cy="19.79" r="1"><animate id="spinner_XyBs" begin="spinner_HiSl.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="12" cy="21" r="1"><animate id="spinner_HiSl" begin="spinner_7gAK.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="1;2;1" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><animateTransform attributeName="transform" type="rotate" dur="6s" values="360 12 12;0 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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="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"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 471 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 368 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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.72,19.9a8,8,0,0,1-6.5-9.79A7.77,7.77,0,0,1,10.4,4.16a8,8,0,0,1,9.49,6.52A1.54,1.54,0,0,0,21.38,12h.13a1.37,1.37,0,0,0,1.38-1.54,11,11,0,1,0-12.7,12.39A1.54,1.54,0,0,0,12,21.34h0A1.47,1.47,0,0,0,10.72,19.9Z"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 520 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M10.72,19.9a8,8,0,0,1-6.5-9.79A7.77,7.77,0,0,1,10.4,4.16a8,8,0,0,1,9.49,6.52A1.54,1.54,0,0,0,21.38,12h.13a1.37,1.37,0,0,0,1.38-1.54,11,11,0,1,0-12.7,12.39A1.54,1.54,0,0,0,12,21.34h0A1.47,1.47,0,0,0,10.72,19.9Z"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 417 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" r="3"><animate id="spinner_qFRN" begin="0;spinner_OcgL.end+0.25s" attributeName="cy" calcMode="spline" dur="0.6s" values="12;6;12" keySplines=".33,.66,.66,1;.33,0,.66,.33"/></circle><circle cx="12" cy="12" r="3"><animate begin="spinner_qFRN.begin+0.1s" attributeName="cy" calcMode="spline" dur="0.6s" values="12;6;12" keySplines=".33,.66,.66,1;.33,0,.66,.33"/></circle><circle cx="20" cy="12" r="3"><animate id="spinner_OcgL" begin="spinner_qFRN.begin+0.2s" attributeName="cy" calcMode="spline" dur="0.6s" values="12;6;12" keySplines=".33,.66,.66,1;.33,0,.66,.33"/></circle></svg>

After

Width:  |  Height:  |  Size: 664 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" r="3" opacity="1"><animate id="spinner_qYjJ" begin="0;spinner_t4KZ.end-0.25s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></circle><circle cx="12" cy="12" r="3" opacity=".4"><animate begin="spinner_qYjJ.begin+0.15s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></circle><circle cx="20" cy="12" r="3" opacity=".3"><animate id="spinner_t4KZ" begin="spinner_qYjJ.begin+0.3s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 577 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" r="0"><animate begin="0;spinner_z0Or.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/><animate begin="spinner_OLMs.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/><animate begin="spinner_UHR2.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/><animate id="spinner_lo66" begin="spinner_Aguh.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/><animate id="spinner_z0Or" begin="spinner_lo66.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/></circle><circle cx="4" cy="12" r="3"><animate begin="0;spinner_z0Or.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/><animate begin="spinner_OLMs.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/><animate id="spinner_JsnR" begin="spinner_UHR2.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/><animate id="spinner_Aguh" begin="spinner_JsnR.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/><animate begin="spinner_Aguh.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/></circle><circle cx="12" cy="12" r="3"><animate begin="0;spinner_z0Or.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/><animate id="spinner_hSjk" begin="spinner_OLMs.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/><animate id="spinner_UHR2" begin="spinner_hSjk.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/><animate begin="spinner_UHR2.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/><animate begin="spinner_Aguh.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/></circle><circle cx="20" cy="12" r="3"><animate id="spinner_4v5M" begin="0;spinner_z0Or.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="3;0" fill="freeze"/><animate id="spinner_OLMs" begin="spinner_4v5M.end" attributeName="cx" dur="0.001s" values="20;4" fill="freeze"/><animate begin="spinner_OLMs.end" attributeName="r" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="0;3" fill="freeze"/><animate begin="spinner_UHR2.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="4;12" fill="freeze"/><animate begin="spinner_Aguh.end" attributeName="cx" calcMode="spline" dur="0.5s" keySplines=".36,.6,.31,1" values="12;20" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="3"/><g><circle cx="4" cy="12" r="3"/><circle cx="20" cy="12" r="3"/><animateTransform attributeName="transform" type="rotate" calcMode="spline" dur="1s" keySplines=".36,.6,.31,1;.36,.6,.31,1" values="0 12 12;180 12 12;360 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 353 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" r="1.5"><animate attributeName="r" dur="0.75s" values="1.5;3;1.5" repeatCount="indefinite"/></circle><circle cx="12" cy="12" r="3"><animate attributeName="r" dur="0.75s" values="3;1.5;3" repeatCount="indefinite"/></circle><circle cx="20" cy="12" r="1.5"><animate attributeName="r" dur="0.75s" values="1.5;3;1.5" repeatCount="indefinite"/></circle></svg>

After

Width:  |  Height:  |  Size: 437 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" r="3"><animate id="spinner_jObz" begin="0;spinner_vwSQ.end-0.25s" attributeName="r" dur="0.75s" values="3;.2;3"/></circle><circle cx="12" cy="12" r="3"><animate begin="spinner_jObz.end-0.6s" attributeName="r" dur="0.75s" values="3;.2;3"/></circle><circle cx="20" cy="12" r="3"><animate id="spinner_vwSQ" begin="spinner_jObz.end-0.45s" attributeName="r" dur="0.75s" values="3;.2;3"/></circle></svg>

After

Width:  |  Height:  |  Size: 481 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><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"/><animateTransform attributeName="transform" type="rotate" calcMode="discrete" dur="0.75s" values="0 12 12;30 12 12;60 12 12;90 12 12;120 12 12;150 12 12;180 12 12;210 12 12;240 12 12;270 12 12;300 12 12;330 12 12;360 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 670 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="3" r="0"><animate id="spinner_6RAU" begin="0;spinner_GErc.end-0.5s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="16.50" cy="4.21" r="0"><animate id="spinner_khXL" begin="spinner_6RAU.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="7.50" cy="4.21" r="0"><animate id="spinner_GErc" begin="spinner_JEaM.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="19.79" cy="7.50" r="0"><animate id="spinner_9orP" begin="spinner_khXL.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="4.21" cy="7.50" r="0"><animate id="spinner_JEaM" begin="spinner_RwRf.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="21.00" cy="12.00" r="0"><animate id="spinner_W8J5" begin="spinner_9orP.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="3.00" cy="12.00" r="0"><animate id="spinner_RwRf" begin="spinner_tByH.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="19.79" cy="16.50" r="0"><animate id="spinner_tedm" begin="spinner_W8J5.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="4.21" cy="16.50" r="0"><animate id="spinner_tByH" begin="spinner_c3Lr.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="16.50" cy="19.79" r="0"><animate id="spinner_QxRo" begin="spinner_tedm.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="7.50" cy="19.79" r="0"><animate id="spinner_c3Lr" begin="spinner_PW3C.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle><circle cx="12" cy="21" r="0"><animate id="spinner_PW3C" begin="spinner_QxRo.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keySplines=".27,.42,.37,.99;.53,0,.61,.73"/></circle></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="3" r="0"><animate id="spinner_318l" begin="0;spinner_cvkU.end-0.5s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="16.50" cy="4.21" r="0"><animate id="spinner_g5Gj" begin="spinner_318l.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="7.50" cy="4.21" r="0"><animate id="spinner_cvkU" begin="spinner_Uuk0.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="19.79" cy="7.50" r="0"><animate id="spinner_e8rM" begin="spinner_g5Gj.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="4.21" cy="7.50" r="0"><animate id="spinner_Uuk0" begin="spinner_z7ol.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="21.00" cy="12.00" r="0"><animate id="spinner_MooL" begin="spinner_e8rM.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="3.00" cy="12.00" r="0"><animate id="spinner_z7ol" begin="spinner_KEoo.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="19.79" cy="16.50" r="0"><animate id="spinner_btyV" begin="spinner_MooL.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="4.21" cy="16.50" r="0"><animate id="spinner_KEoo" begin="spinner_1IYD.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="16.50" cy="19.79" r="0"><animate id="spinner_1sIS" begin="spinner_btyV.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="7.50" cy="19.79" r="0"><animate id="spinner_1IYD" begin="spinner_NWhh.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle><circle cx="12" cy="21" r="0"><animate id="spinner_NWhh" begin="spinner_1sIS.begin+0.1s" attributeName="r" calcMode="spline" dur="0.6s" values="0;2;0" keyTimes="0;.2;1" keySplines="0,1,0,1;.53,0,.61,.73" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><circle cx="3" cy="12" r="2"/><circle cx="21" cy="12" r="2"/><circle cx="12" cy="21" r="2"/><circle cx="12" cy="3" r="2"/><circle cx="5.64" cy="5.64" r="2"/><circle cx="18.36" cy="18.36" r="2"/><circle cx="5.64" cy="18.36" r="2"/><circle cx="18.36" cy="5.64" r="2"/><animateTransform attributeName="transform" type="rotate" dur="1.5s" values="0 12 12;360 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 462 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 465 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,20 @@
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

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="4" width="6" height="14" opacity="1"><animate id="spinner_rQ7m" begin="0;spinner_2dMV.end-0.25s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect><rect x="9" y="4" width="6" height="14" opacity=".4"><animate begin="spinner_rQ7m.begin+0.15s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect><rect x="17" y="4" width="6" height="14" opacity=".3"><animate id="spinner_2dMV" begin="spinner_rQ7m.begin+0.3s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect></svg>

After

Width:  |  Height:  |  Size: 603 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><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)"/><animateTransform attributeName="transform" type="rotate" calcMode="discrete" dur="0.75s" values="0 12 12;30 12 12;60 12 12;90 12 12;120 12 12;150 12 12;180 12 12;210 12 12;240 12 12;270 12 12;300 12 12;330 12 12;360 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 872 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="4" width="6" height="14" opacity="1"><animate id="spinner_aqiq" begin="0;spinner_xVBj.end-0.25s" attributeName="y" dur="0.75s" values="1;5" fill="freeze"/><animate begin="0;spinner_xVBj.end-0.25s" attributeName="height" dur="0.75s" values="22;14" fill="freeze"/><animate begin="0;spinner_xVBj.end-0.25s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect><rect x="9" y="4" width="6" height="14" opacity=".4"><animate begin="spinner_aqiq.begin+0.15s" attributeName="y" dur="0.75s" values="1;5" fill="freeze"/><animate begin="spinner_aqiq.begin+0.15s" attributeName="height" dur="0.75s" values="22;14" fill="freeze"/><animate begin="spinner_aqiq.begin+0.15s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect><rect x="17" y="4" width="6" height="14" opacity=".3"><animate id="spinner_xVBj" begin="spinner_aqiq.begin+0.3s" attributeName="y" dur="0.75s" values="1;5" fill="freeze"/><animate begin="spinner_aqiq.begin+0.3s" attributeName="height" dur="0.75s" values="22;14" fill="freeze"/><animate begin="spinner_aqiq.begin+0.3s" attributeName="opacity" dur="0.75s" values="1;.2" fill="freeze"/></rect></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="6" width="2.8" height="12"><animate begin="spinner_Diec.begin+0.4s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/><animate begin="spinner_Diec.begin+0.4s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/></rect><rect x="5.8" y="6" width="2.8" height="12"><animate begin="spinner_Diec.begin+0.2s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/><animate begin="spinner_Diec.begin+0.2s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/></rect><rect x="10.6" y="6" width="2.8" height="12"><animate id="spinner_Diec" begin="0;spinner_dm8s.end-0.1s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/><animate begin="0;spinner_dm8s.end-0.1s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/></rect><rect x="15.4" y="6" width="2.8" height="12"><animate begin="spinner_Diec.begin+0.2s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/><animate begin="spinner_Diec.begin+0.2s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/></rect><rect x="20.2" y="6" width="2.8" height="12"><animate id="spinner_dm8s" begin="spinner_Diec.begin+0.4s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/><animate begin="spinner_Diec.begin+0.4s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".14,.73,.34,1;.65,.26,.82,.45"/></rect></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="6" width="2.8" height="12"><animate id="spinner_CcmT" begin="0;spinner_IzZB.end-0.1s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/><animate begin="0;spinner_IzZB.end-0.1s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/></rect><rect x="5.8" y="6" width="2.8" height="12"><animate begin="spinner_CcmT.begin+0.1s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/><animate begin="spinner_CcmT.begin+0.1s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/></rect><rect x="10.6" y="6" width="2.8" height="12"><animate begin="spinner_CcmT.begin+0.2s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/><animate begin="spinner_CcmT.begin+0.2s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/></rect><rect x="15.4" y="6" width="2.8" height="12"><animate begin="spinner_CcmT.begin+0.3s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/><animate begin="spinner_CcmT.begin+0.3s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/></rect><rect x="20.2" y="6" width="2.8" height="12"><animate id="spinner_IzZB" begin="spinner_CcmT.begin+0.4s" attributeName="y" calcMode="spline" dur="0.6s" values="6;1;6" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/><animate begin="spinner_CcmT.begin+0.4s" attributeName="height" calcMode="spline" dur="0.6s" values="12;22;12" keySplines=".36,.61,.3,.98;.36,.61,.3,.98"/></rect></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1.5" y="1.5" rx="1" width="9" height="9"><animate id="spinner_M16P" begin="0;spinner_wNI2.end+0.15s" attributeName="x" dur="0.6s" values="1.5;.5;1.5" keyTimes="0;.2;1"/><animate begin="0;spinner_wNI2.end+0.15s" attributeName="y" dur="0.6s" values="1.5;.5;1.5" keyTimes="0;.2;1"/><animate begin="0;spinner_wNI2.end+0.15s" attributeName="width" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/><animate begin="0;spinner_wNI2.end+0.15s" attributeName="height" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/></rect><rect x="13.5" y="1.5" rx="1" width="9" height="9"><animate begin="spinner_M16P.begin+0.15s" attributeName="x" dur="0.6s" values="13.5;12.5;13.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.15s" attributeName="y" dur="0.6s" values="1.5;.5;1.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.15s" attributeName="width" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.15s" attributeName="height" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/></rect><rect x="13.5" y="13.5" rx="1" width="9" height="9"><animate begin="spinner_M16P.begin+0.3s" attributeName="x" dur="0.6s" values="13.5;12.5;13.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.3s" attributeName="y" dur="0.6s" values="13.5;12.5;13.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.3s" attributeName="width" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.3s" attributeName="height" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/></rect><rect x="1.5" y="13.5" rx="1" width="9" height="9"><animate id="spinner_wNI2" begin="spinner_M16P.begin+0.45s" attributeName="x" dur="0.6s" values="1.5;.5;1.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.45s" attributeName="y" dur="0.6s" values="13.5;12.5;13.5" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.45s" attributeName="width" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/><animate begin="spinner_M16P.begin+0.45s" attributeName="height" dur="0.6s" values="9;11;9" keyTimes="0;.2;1"/></rect></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" rx="1" width="10" height="10"><animate id="spinner_FFyM" begin="0;spinner_HDCY.end" attributeName="x" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_AIvE" begin="spinner_1FwE.end" attributeName="y" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_wWCL" begin="spinner_gH4o.end" attributeName="x" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_S3Gg" begin="spinner_Q0bx.end" attributeName="y" dur="0.2s" values="13;1" fill="freeze"/></rect><rect x="1" y="13" rx="1" width="10" height="10"><animate id="spinner_1FwE" begin="spinner_FFyM.end" attributeName="y" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_gH4o" begin="spinner_AIvE.end" attributeName="x" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_Q0bx" begin="spinner_wWCL.end" attributeName="y" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_HDCY" begin="spinner_S3Gg.end" attributeName="x" dur="0.2s" values="13;1" fill="freeze"/></rect></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" rx="1" width="10" height="10"><animate id="spinner_c7A9" begin="0;spinner_23zP.end" attributeName="x" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_Acnw" begin="spinner_ZmWi.end" attributeName="y" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_iIcm" begin="spinner_zfQN.end" attributeName="x" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_WX4U" begin="spinner_rRAc.end" attributeName="y" dur="0.2s" values="13;1" fill="freeze"/></rect><rect x="1" y="13" rx="1" width="10" height="10"><animate id="spinner_YLx7" begin="spinner_c7A9.end" attributeName="y" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_vwnJ" begin="spinner_Acnw.end" attributeName="x" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_KQuy" begin="spinner_iIcm.end" attributeName="y" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_arKy" begin="spinner_WX4U.end" attributeName="x" dur="0.2s" values="13;1" fill="freeze"/></rect><rect x="13" y="13" rx="1" width="10" height="10"><animate id="spinner_ZmWi" begin="spinner_YLx7.end" attributeName="x" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_zfQN" begin="spinner_vwnJ.end" attributeName="y" dur="0.2s" values="13;1" fill="freeze"/><animate id="spinner_rRAc" begin="spinner_KQuy.end" attributeName="x" dur="0.2s" values="1;13" fill="freeze"/><animate id="spinner_23zP" begin="spinner_arKy.end" attributeName="y" dur="0.2s" values="1;13" fill="freeze"/></rect></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" width="7.33" height="7.33"><animate id="spinner_oJFS" begin="0;spinner_5T1J.end+0.2s" attributeName="x" dur="0.6s" values="1;4;1"/><animate begin="0;spinner_5T1J.end+0.2s" attributeName="y" dur="0.6s" values="1;4;1"/><animate begin="0;spinner_5T1J.end+0.2s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="0;spinner_5T1J.end+0.2s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="8.33" y="1" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.1s" attributeName="x" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="y" dur="0.6s" values="1;4;1"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="1" y="8.33" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.1s" attributeName="x" dur="0.6s" values="1;4;1"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="y" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.1s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="15.66" y="1" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.2s" attributeName="x" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="y" dur="0.6s" values="1;4;1"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="8.33" y="8.33" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.2s" attributeName="x" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="y" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="1" y="15.66" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.2s" attributeName="x" dur="0.6s" values="1;4;1"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="y" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.2s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="15.66" y="8.33" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.3s" attributeName="x" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="y" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="8.33" y="15.66" width="7.33" height="7.33"><animate begin="spinner_oJFS.begin+0.3s" attributeName="x" dur="0.6s" values="8.33;11.33;8.33"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="y" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.3s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect><rect x="15.66" y="15.66" width="7.33" height="7.33"><animate id="spinner_5T1J" begin="spinner_oJFS.begin+0.4s" attributeName="x" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.4s" attributeName="y" dur="0.6s" values="15.66;18.66;15.66"/><animate begin="spinner_oJFS.begin+0.4s" attributeName="width" dur="0.6s" values="7.33;1.33;7.33"/><animate begin="spinner_oJFS.begin+0.4s" attributeName="height" dur="0.6s" values="7.33;1.33;7.33"/></rect></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><ellipse cx="12" cy="5" rx="4" ry="4"><animate id="spinner_jbYs" begin="0;spinner_JZdr.end" attributeName="cy" calcMode="spline" dur="0.375s" values="5;20" keySplines=".33,0,.66,.33" fill="freeze"/><animate begin="spinner_jbYs.end" attributeName="rx" calcMode="spline" dur="0.05s" values="4;4.8;4" keySplines=".33,0,.66,.33;.33,.66,.66,1"/><animate begin="spinner_jbYs.end" attributeName="ry" calcMode="spline" dur="0.05s" values="4;3;4" keySplines=".33,0,.66,.33;.33,.66,.66,1"/><animate id="spinner_ADF4" begin="spinner_jbYs.end" attributeName="cy" calcMode="spline" dur="0.025s" values="20;20.5" keySplines=".33,0,.66,.33"/><animate id="spinner_JZdr" begin="spinner_ADF4.end" attributeName="cy" calcMode="spline" dur="0.4s" values="20.5;5" keySplines=".33,.66,.66,1"/></ellipse></svg>

After

Width:  |  Height:  |  Size: 848 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path 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"/><rect x="11" y="6" rx="1" width="2" height="7"><animateTransform attributeName="transform" type="rotate" dur="9s" values="0 12 12;360 12 12" repeatCount="indefinite"/></rect><rect x="11" y="11" rx="1" width="2" height="9"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></rect></svg>

After

Width:  |  Height:  |  Size: 508 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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"/><circle cx="12" cy="2.5" r="1.5"><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></circle></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2,12A10.94,10.94,0,0,1,5,4.65c-.21-.19-.42-.36-.62-.55h0A11,11,0,0,0,12,23c.34,0,.67,0,1-.05C6,23,2,17.74,2,12Z"><animateTransform attributeName="transform" type="rotate" dur="0.6s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M2,12A11.2,11.2,0,0,1,13,1.05C12.67,1,12.34,1,12,1a11,11,0,0,0,0,22c.34,0,.67,0,1-.05C6,23,2,17.74,2,12Z"><animateTransform attributeName="transform" type="rotate" dur="0.6s" values="0 12 12;360 12 12" repeatCount="indefinite"/></path></svg>

After

Width:  |  Height:  |  Size: 311 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><defs><filter id="spinner-gF00"><feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="y"/><feColorMatrix in="y" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="z"/><feBlend in="SourceGraphic" in2="z"/></filter></defs><g filter="url(#spinner-gF00)"><circle cx="4" cy="12" r="3"><animate attributeName="cx" calcMode="spline" dur="0.75s" values="4;9;4" keySplines=".56,.52,.17,.98;.56,.52,.17,.98" repeatCount="indefinite"/><animate attributeName="r" calcMode="spline" dur="0.75s" values="3;8;3" keySplines=".56,.52,.17,.98;.56,.52,.17,.98" repeatCount="indefinite"/></circle><circle cx="15" cy="12" r="8"><animate attributeName="cx" calcMode="spline" dur="0.75s" values="15;20;15" keySplines=".56,.52,.17,.98;.56,.52,.17,.98" repeatCount="indefinite"/><animate attributeName="r" calcMode="spline" dur="0.75s" values="8;3;8" keySplines=".56,.52,.17,.98;.56,.52,.17,.98" repeatCount="indefinite"/></circle></g></svg>

After

Width:  |  Height:  |  Size: 1006 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><defs><filter id="spinner-gF01"><feGaussianBlur in="SourceGraphic" stdDeviation="1" result="y"/><feColorMatrix in="y" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="z"/><feBlend in="SourceGraphic" in2="z"/></filter></defs><g filter="url(#spinner-gF01)"><circle cx="5" cy="12" r="4"><animate attributeName="cx" calcMode="spline" dur="2s" values="5;8;5" keySplines=".36,.62,.43,.99;.79,0,.58,.57" repeatCount="indefinite"/></circle><circle cx="19" cy="12" r="4"><animate attributeName="cx" calcMode="spline" dur="2s" values="19;16;19" keySplines=".36,.62,.43,.99;.79,0,.58,.57" repeatCount="indefinite"/></circle><animateTransform attributeName="transform" type="rotate" dur="0.75s" values="0 12 12;360 12 12" repeatCount="indefinite"/></g></svg>

After

Width:  |  Height:  |  Size: 831 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="0"><animate id="spinner_lNK6" begin="0;spinner_NDtD.begin+0.6s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="0;spinner_NDtD.begin+0.6s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle><circle cx="12" cy="12" r="0"><animate id="spinner_NDtD" begin="spinner_lNK6.begin+0.6s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="spinner_lNK6.begin+0.6s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 775 B

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="0"><animate id="spinner_0Nme" begin="0;spinner_ITag.begin+0.4s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="0;spinner_ITag.begin+0.4s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle><circle cx="12" cy="12" r="0"><animate id="spinner_f83A" begin="spinner_0Nme.begin+0.4s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="spinner_0Nme.begin+0.4s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle><circle cx="12" cy="12" r="0"><animate id="spinner_ITag" begin="spinner_0Nme.begin+0.8s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="spinner_0Nme.begin+0.8s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="0"><animate id="spinner_kIfO" begin="0;spinner_xBIM.end" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="0;spinner_xBIM.end" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle><circle cx="12" cy="12" r="0"><animate id="spinner_Pbsh" begin="spinner_kIfO.begin+0.2s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="spinner_kIfO.begin+0.2s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle><circle cx="12" cy="12" r="0"><animate id="spinner_xBIM" begin="spinner_kIfO.begin+0.4s" attributeName="r" calcMode="spline" dur="1.2s" values="0;11" keySplines=".52,.6,.25,.99" fill="freeze"/><animate begin="spinner_kIfO.begin+0.4s" attributeName="opacity" calcMode="spline" dur="1.2s" values="1;0" keySplines=".52,.6,.25,.99" fill="freeze"/></circle></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

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