diff --git a/.gitignore b/.gitignore index feee598a..c0416284 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ inst/examples/**/rsconnect .vscode *.icloud docs + +/.quarto/ diff --git a/DESCRIPTION b/DESCRIPTION index 0d6d2cea..d67e90e4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: bs4Dash Type: Package Title: A 'Bootstrap 4' Version of 'shinydashboard' -Version: 2.3.3 +Version: 2.3.4 Authors@R: c( person("David", "Granjon", email = "dgranjon@ymail.com", role = c("aut", "cre")), person(family = "RinteRface", role = "cph"), @@ -11,7 +11,7 @@ Maintainer: David Granjon Description: Make 'Bootstrap 4' Shiny dashboards. Use the full power of 'AdminLTE3', a dashboard template built on top of 'Bootstrap 4' . -URL: https://rinterface.github.io/bs4Dash/index.html, https://github.com/RinteRface/bs4Dash +URL: https://rinterface.github.io/bs4Dash/index.html, https://github.com/RinteRface/bs4Dash, https://bs4dash.rinterface.com/ BugReports: https://github.com/RinteRface/bs4Dash/issues License: GPL (>= 2) | file LICENSE Imports: @@ -32,7 +32,7 @@ Suggests: DT, thematic (>= 0.1.2) Encoding: UTF-8 -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 VignetteBuilder: knitr Collate: 'feedbacks.R' @@ -56,3 +56,5 @@ Collate: 'skinSelector.R' 'utils.R' RdMacros: lifecycle +Depends: + R (>= 2.10) diff --git a/NEWS.md b/NEWS.md index ceb7eb23..0d8f2315 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +# bs4Dash 2.3.4 + +- Added shinylive to support documentation examples. + +## Minor change +- Update jquery-ui to 1.13.2. Thanks @biognosys-so. +- Fix CRAN NOTES. + # bs4Dash 2.3.3 ## Breaking change (potential) diff --git a/R/sysdata.rda b/R/sysdata.rda new file mode 100644 index 00000000..55b073f9 Binary files /dev/null and b/R/sysdata.rda differ diff --git a/R/tabs.R b/R/tabs.R index a2a4cbc7..67e39ff9 100644 --- a/R/tabs.R +++ b/R/tabs.R @@ -261,11 +261,11 @@ tabsetPanel <- function(..., id = NULL, selected = NULL, -#' Insert a \link{tabPanel} in a \link{tabsetPanel} +#' Insert a \link[shiny]{tabPanel} in a \link{tabsetPanel} #' #' @param inputId \link{tabsetPanel} id. -#' @param tab \link{tabPanel} to insert. -#' @param target \link{tabPanel} after of before which the new tab will be inserted. +#' @param tab \link[shiny]{tabPanel} to insert. +#' @param target \link[shiny]{tabPanel} after of before which the new tab will be inserted. #' @param position Insert before or after: \code{c("before", "after")}. #' @param select Whether to select the newly inserted tab. FALSE by default. #' @param session Shiny session object. diff --git a/R/utils.R b/R/utils.R index 2e06a257..7e8b4574 100644 --- a/R/utils.R +++ b/R/utils.R @@ -748,3 +748,17 @@ get_parent_args <- function() { cl <- sys.call(-3) as.list(cl)[-1] } + +# For shinylive examples +create_link_iframe <- function(link) { + shiny::tags$iframe( + class = "html-fill-item", + src = link, + height = "800", + width = "100%", + style = "border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem;", + allowfullscreen = "", + allow = "autoplay", + `data-external` = "1" + ) +} \ No newline at end of file diff --git a/README.md b/README.md index 1af7de88..02ddda27 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
- +

@@ -59,7 +59,7 @@ server <- function(input, output) { shinyApp(ui, server) ``` -Starting from v2.0.0, moving to `{bs4Dash}` is rather simple: +Moving to `{bs4Dash}` is rather simple, as we just replace `library(shinydashboard)`: ```r library(bs4Dash) @@ -92,14 +92,6 @@ server <- function(input, output) { shinyApp(ui, server) ``` - -## Upgrading bs4Dash to 2.0.0 -- `{bs4Dash}` is undergoing major rework to make it easier to come from `{shinydashboard}`. The current development version 2.0.0 provides a 1:1 supports, in other word moving from `{shinydashboard}` to `{bs4Dash}` is accomplished by changing `library(shinydashboard)` to `library(bs4Dash)`. - -- `{bs4Dash}` v2.0.0 also provides 1:1 with `{shinydashboardPlus}` to ease compatibility. - -- Apps built with `{bs4Dash}` version <= 0.5.0 are definitely not compatible with v2.0.0 due to substantial breaking changes in the API. We advise users to keep the old version for old apps and move to to the new version for newer apps. - ## Installation ```r @@ -110,8 +102,6 @@ install.packages("bs4Dash") ``` ## Demo - -See a working example on shinyapps.io [here](https://dgranjon.shinyapps.io/bs4DashDemo/). You may also run: ```r diff --git a/_pkgdown.yml b/_pkgdown.yml index 94b212f8..d301dc82 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,3 +1,7 @@ +template: + bootstrap: 5 + +url: https://bs4dash.rinterface.com/ reference: - title: Basic dashboard functions desc: Dashboard skeleton functions @@ -240,8 +244,7 @@ navbar: articles: - title: User guide - desc: ~ - navbar: User Guide + navbar: ~ contents: - '`step-by-step`' - '`improved-boxes`' @@ -252,7 +255,9 @@ articles: news: releases: - - text: "bs4Dash 2.4.0.9000" + - text: "bs4Dash 2.3.4" + - text: "bs4Dash 2.3.3" + - text: "bs4Dash 2.3.0" - text: "bs4Dash 2.2.1" - text: "bs4Dash 2.1.0" - text: "bs4Dash 2.0.3" diff --git a/cran-comments.md b/cran-comments.md index abe17c18..157bad12 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -9,5 +9,13 @@ There were no ERRORs or WARNINGs or NOTEs. ## Note -This release will fixe the NOTES on https://cran.r-project.org/web/checks/check_results_bs4Dash.html. -Update: re-submissiom fixing issue with `omicsTools` reverse dependency. \ No newline at end of file +Fix a 3 NOTES: + +> Version: 2.3.3 +Check: Rd cross-references +Result: NOTE + Found the following Rd file(s) with Rd \link{} targets missing package + anchors: + insertTab.Rd: tabPanel + Please provide package anchors for all Rd \link{} targets not in the + package itself and the base packages. \ No newline at end of file diff --git a/index.Rmd b/index.Rmd index e22a613a..8b5f11f1 100644 --- a/index.Rmd +++ b/index.Rmd @@ -1,8 +1,11 @@ --- output: github_document +always_allow_html: true --- ```{r setup, include=FALSE} +library(bslib) +library(bs4Dash) knitr::opts_chunk$set(echo = TRUE) ``` @@ -11,32 +14,29 @@ knitr::opts_chunk$set(echo = TRUE) [![R build status](https://github.com/RinteRface/bs4Dash/workflows/R-CMD-check/badge.svg)](https://github.com/RinteRface/bs4Dash/actions) [![version](https://www.r-pkg.org/badges/version/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) [![cranlogs](https://cranlogs.r-pkg.org/badges/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) -[![total](https://cranlogs.r-pkg.org/badges/grand-total/bs4Dash)](https://www.rpackages.io/package/bs4Dash) +[![total](https://cranlogs.r-pkg.org/badges/grand-total/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) [![Codecov test coverage](https://codecov.io/gh/RinteRface/bs4Dash/branch/master/graph/badge.svg)](https://codecov.io/gh/RinteRface/bs4Dash?branch=master) - - > Bootstrap 4 shinydashboard using [AdminLTE3](https://github.com/ColorlibHQ/AdminLTE)
-
- -
+```{r showcase-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/showcase"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" +) +```
- +bs4Dash usage medical dashboard
-
-```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/virtual_patient_v2/", deps = TRUE) -``` - -## New users moving to bs4Dash v2.0.0 +## From shinydashboard to bs4Dash Taking the simple `{shinydashboard}` example: @@ -73,7 +73,7 @@ server <- function(input, output) { shinyApp(ui, server) ``` -Starting from v2.0.0, moving to `{bs4Dash}` is rather simple: +Moving to `{bs4Dash}` is rather simple, as we just replace `library(shinydashboard)`: ```r library(bs4Dash) @@ -106,14 +106,6 @@ server <- function(input, output) { shinyApp(ui, server) ``` - -## Upgrading bs4Dash to 2.0.0 -- `{bs4Dash}` is undergoing major rework to make it easier to come from `{shinydashboard}`. The current development version 2.0.0 provides a 1:1 supports, in other word moving from `{shinydashboard}` to `{bs4Dash}` is accomplished by changing `library(shinydashboard)` to `library(bs4Dash)`. - -- `{bs4Dash}` v2.0.0 also provides 1:1 with `{shinydashboardPlus}` to ease compatibility. - -- Apps built with `{bs4Dash}` version <= 0.5.0 are definitely not compatible with v2.0.0 due to substantial breaking changes in the API. We advise users to keep the old version for old apps and move to to the new version for newer apps. - ## Installation ```r @@ -124,7 +116,6 @@ install.packages("bs4Dash") ``` ## Demo -See a working example on shinyapps.io [here](https://dgranjon.shinyapps.io/bs4DashDemo/). You may also run: ```r diff --git a/index.md b/index.md index 2d9aaa91..20c94cee 100644 --- a/index.md +++ b/index.md @@ -1,43 +1,43 @@ -# bs4Dash -[![R build status](https://github.com/RinteRface/bs4Dash/workflows/R-CMD-check/badge.svg)](https://github.com/RinteRface/bs4Dash/actions) +# bs4Dash + +[![R build +status](https://github.com/RinteRface/bs4Dash/workflows/R-CMD-check/badge.svg)](https://github.com/RinteRface/bs4Dash/actions) [![version](https://www.r-pkg.org/badges/version/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) [![cranlogs](https://cranlogs.r-pkg.org/badges/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) -[![total](https://cranlogs.r-pkg.org/badges/grand-total/bs4Dash)](https://www.rpackages.io/package/bs4Dash) -[![Codecov test coverage](https://codecov.io/gh/RinteRface/bs4Dash/branch/master/graph/badge.svg)](https://codecov.io/gh/RinteRface/bs4Dash?branch=master) - - +[![total](https://cranlogs.r-pkg.org/badges/grand-total/bs4Dash)](https://CRAN.R-project.org/package=bs4Dash) +[![Codecov test +coverage](https://codecov.io/gh/RinteRface/bs4Dash/branch/master/graph/badge.svg)](https://codecov.io/gh/RinteRface/bs4Dash?branch=master) -> Bootstrap 4 shinydashboard using [AdminLTE3](https://github.com/ColorlibHQ/AdminLTE) +> Bootstrap 4 shinydashboard using +> [AdminLTE3](https://github.com/ColorlibHQ/AdminLTE)
-
- +
+
+ +
+ + + + +

- -
- -
+bs4Dash usage medical dashboard -
-
-
- -
-
-## New users moving to bs4Dash v2.0.0 +## From shinydashboard to bs4Dash Taking the simple `{shinydashboard}` example: -```r +``` r library(shiny) library(shinydashboard) @@ -70,9 +70,10 @@ server <- function(input, output) { shinyApp(ui, server) ``` -Starting from v2.0.0, moving to `{bs4Dash}` is rather simple: +Moving to `{bs4Dash}` is rather simple, as we just replace +`library(shinydashboard)`: -```r +``` r library(bs4Dash) ui <- dashboardPage( dashboardHeader(title = "Basic dashboard"), @@ -103,17 +104,9 @@ server <- function(input, output) { shinyApp(ui, server) ``` - -## Upgrading bs4Dash to 2.0.0 -- `{bs4Dash}` is undergoing major rework to make it easier to come from `{shinydashboard}`. The current development version 2.0.0 provides a 1:1 supports, in other word moving from `{shinydashboard}` to `{bs4Dash}` is accomplished by changing `library(shinydashboard)` to `library(bs4Dash)`. - -- `{bs4Dash}` v2.0.0 also provides 1:1 with `{shinydashboardPlus}` to ease compatibility. - -- Apps built with `{bs4Dash}` version <= 0.5.0 are definitely not compatible with v2.0.0 due to substantial breaking changes in the API. We advise users to keep the old version for old apps and move to to the new version for newer apps. - ## Installation -```r +``` r # latest devel version devtools::install_github("RinteRface/bs4Dash") # from CRAN @@ -122,23 +115,25 @@ install.packages("bs4Dash") ## Demo -See a working example on shinyapps.io [here](https://dgranjon.shinyapps.io/bs4DashDemo/). You may also run: -```r +``` r library(bs4Dash) bs4DashGallery() ``` ## Issues -Issues are listed [here](https://github.com/RinteRface/bs4Dash/issues). - +Issues are listed [here](https://github.com/RinteRface/bs4Dash/issues). ## Acknowledgement -I warmly thank [Glyphicons](https://www.glyphicons.com) creator for providing them for free with Bootstrap. +I warmly thank [Glyphicons](https://www.glyphicons.com) creator for +providing them for free with Bootstrap. ## Code of Conduct - -Please note that the bs4Dash project is released with a [Contributor Code of Conduct](https:/contributor-covenant.org/version/2/0/CODE_OF_CONDUCT.html). By contributing to this project, you agree toabide by its terms. + +Please note that the bs4Dash project is released with a [Contributor +Code of +Conduct](https:/contributor-covenant.org/version/2/0/CODE_OF_CONDUCT.html). +By contributing to this project, you agree toabide by its terms. diff --git a/inst/bs4Dash-2.3.3/bs4Dash.css b/inst/bs4Dash-2.3.4/bs4Dash.css similarity index 100% rename from inst/bs4Dash-2.3.3/bs4Dash.css rename to inst/bs4Dash-2.3.4/bs4Dash.css diff --git a/inst/bs4Dash-2.3.3/bs4Dash.js b/inst/bs4Dash-2.3.4/bs4Dash.js similarity index 99% rename from inst/bs4Dash-2.3.3/bs4Dash.js rename to inst/bs4Dash-2.3.4/bs4Dash.js index 251493ac..06224759 100644 --- a/inst/bs4Dash-2.3.3/bs4Dash.js +++ b/inst/bs4Dash-2.3.4/bs4Dash.js @@ -932,7 +932,7 @@ $(function () { break; default: console.warn(`${config.status} does not belong to allowed statuses!`) } - + closeButton = ''; if (config.closable) { diff --git a/inst/bs4Dash-2.3.3/bs4Dash.min.js b/inst/bs4Dash-2.3.4/bs4Dash.min.js similarity index 100% rename from inst/bs4Dash-2.3.3/bs4Dash.min.js rename to inst/bs4Dash-2.3.4/bs4Dash.min.js diff --git a/inst/bs4Dash-2.3.3/bs4Dash.min.js.map b/inst/bs4Dash-2.3.4/bs4Dash.min.js.map similarity index 100% rename from inst/bs4Dash-2.3.3/bs4Dash.min.js.map rename to inst/bs4Dash-2.3.4/bs4Dash.min.js.map diff --git a/inst/shinylive/tools.R b/inst/shinylive/tools.R new file mode 100644 index 00000000..066918d4 --- /dev/null +++ b/inst/shinylive/tools.R @@ -0,0 +1,19 @@ +pak::pak("parmsam/r-shinylive@feat/encode-decode-url") + +create_shinylive_links <- function(path) { + + dirs <- list.dirs(path)[-1] + + vapply( + list.dirs(path)[-1], + shinylive:::url_encode_dir, + FUN.VALUE = character(1) + ) +} + +create_vignettes_links <- function() { + create_shinylive_links("inst/examples/vignettes-demos") +} + +shinylive_links <- create_vignettes_links() +usethis::use_data(shinylive_links, internal = TRUE, overwrite = TRUE) \ No newline at end of file diff --git a/man/insertTab.Rd b/man/insertTab.Rd index f91a6f57..1ec5f748 100644 --- a/man/insertTab.Rd +++ b/man/insertTab.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/tabs.R \name{insertTab} \alias{insertTab} -\title{Insert a \link{tabPanel} in a \link{tabsetPanel}} +\title{Insert a \link[shiny]{tabPanel} in a \link{tabsetPanel}} \usage{ insertTab( inputId, @@ -16,9 +16,9 @@ insertTab( \arguments{ \item{inputId}{\link{tabsetPanel} id.} -\item{tab}{\link{tabPanel} to insert.} +\item{tab}{\link[shiny]{tabPanel} to insert.} -\item{target}{\link{tabPanel} after of before which the new tab will be inserted.} +\item{target}{\link[shiny]{tabPanel} after of before which the new tab will be inserted.} \item{position}{Insert before or after: \code{c("before", "after")}.} @@ -27,7 +27,7 @@ insertTab( \item{session}{Shiny session object.} } \description{ -Insert a \link{tabPanel} in a \link{tabsetPanel} +Insert a \link[shiny]{tabPanel} in a \link{tabsetPanel} } \examples{ if (interactive()) { diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 5f3a3db9..00000000 --- a/netlify.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] - publish = "docs" diff --git a/pkgdown/extra.css b/pkgdown/extra.css index ee68e323..1f23c93f 100644 --- a/pkgdown/extra.css +++ b/pkgdown/extra.css @@ -902,3 +902,27 @@ fieldset:disabled a.btn { -moz-transition: -moz-transform 0.3s 0.7s, opacity 0s 0.7s; transition: transform 0.3s 0.7s, opacity 0s 0.7s; } + +/* bslib cards */ +.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen="true"]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border="true"]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius="true"]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen="true"]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,0.15);margin:0.2rem 0.4rem;padding:0.55rem !important;font-size:.8rem;cursor:pointer;opacity:0.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen="false"]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media (max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:0.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:0.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}} + +/* fill css for fullscreen cards */ +.html-fill-container { + display: flex; + flex-direction: column; + /* Prevent the container from expanding vertically or horizontally beyond its + parent's constraints. */ + min-height: 0; + min-width: 0; +} +.html-fill-container > .html-fill-item { + /* Fill items can grow and shrink freely within + available vertical space in fillable container */ + flex: 1 1 auto; + min-height: 0; + min-width: 0; +} +.html-fill-container > :not(.html-fill-item) { + /* Prevent shrinking or growing of non-fill items */ + flex: 0 0 auto; +} diff --git a/pkgdown/extra.js b/pkgdown/extra.js index c4e6f3ef..357a19f3 100644 --- a/pkgdown/extra.js +++ b/pkgdown/extra.js @@ -114,4 +114,20 @@ jQuery(document).ready(function ($) { (label.offset().left > resizeElement.offset().left + resizeElement.outerWidth()) ? label.removeClass('is-hidden') : label.addClass('is-hidden'); } } -}); \ No newline at end of file +}); + +/*! bslib 0.7.0.9000 | (c) 2012-2024 RStudio, PBC. | License: MIT + file LICENSE */ +"use strict";(()=>{var f=(r,e)=>()=>(r&&(e=r(r=0)),e);var X=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var k=(r,e,t)=>{if(!e.has(r))throw TypeError("Cannot "+t)};var v=(r,e,t)=>(k(r,e,"read from private field"),t?t.call(r):e.get(r)),H=(r,e,t)=>{if(e.has(r))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(r):e.set(r,t)};var O=(r,e,t)=>(k(r,e,"access private method"),t);var h=(r,e,t)=>new Promise((i,n)=>{var s=o=>{try{d(t.next(o))}catch(b){n(b)}},l=o=>{try{d(t.throw(o))}catch(b){n(b)}},d=o=>o.done?i(o.value):Promise.resolve(o.value).then(s,l);d((t=t.apply(r,e)).next())});function y(r,e){u&&u.inputBindings.register(new r,"bslib."+e)}function _(r,e){window.bslib=window.bslib||{},window.bslib[r]?console.error(`[bslib] Global window.bslib.${r} was already defined, using previous definition.`):window.bslib[r]=e}function w(r,e){return Object.prototype.hasOwnProperty.call(r,e)&&r[e]!==void 0}function U(r){let e=["a[href]","area[href]","button","details summary","input","iframe","select","textarea",'[contentEditable=""]','[contentEditable="true"]','[contentEditable="TRUE"]',"[tabindex]"],t=[':not([tabindex="-1"])',":not([disabled])"],i=e.map(s=>s+t.join("")),n=r.querySelectorAll(i.join(", "));return Array.from(n)}function E(...r){return h(this,null,function*(){if(!u)throw new Error("This function must be called in a Shiny app.");return u.renderContentAsync?yield u.renderContentAsync.apply(null,r):yield u.renderContent.apply(null,r)})}var u,m,L=f(()=>{"use strict";u=window.Shiny,m=u?u.InputBinding:class{}});var R,B=f(()=>{"use strict";L();R=class extends m{find(e){return $(e).find(".accordion.bslib-accordion-input")}getValue(e){let i=this._getItemInfo(e).filter(n=>n.isOpen()).map(n=>n.value);return i.length===0?null:i}subscribe(e,t){$(e).on("shown.bs.collapse.accordionInputBinding hidden.bs.collapse.accordionInputBinding",function(i){t(!0)})}unsubscribe(e){$(e).off(".accordionInputBinding")}receiveMessage(e,t){return h(this,null,function*(){let i=t.method;if(i==="set")this._setItems(e,t);else if(i==="open")this._openItems(e,t);else if(i==="close")this._closeItems(e,t);else if(i==="remove")this._removeItem(e,t);else if(i==="insert")yield this._insertItem(e,t);else if(i==="update")yield this._updateItem(e,t);else throw new Error(`Method not yet implemented: ${i}`)})}_setItems(e,t){let i=this._getItemInfo(e),n=this._getValues(e,i,t.values);i.forEach(s=>{n.indexOf(s.value)>-1?s.show():s.hide()})}_openItems(e,t){let i=this._getItemInfo(e),n=this._getValues(e,i,t.values);i.forEach(s=>{n.indexOf(s.value)>-1&&s.show()})}_closeItems(e,t){let i=this._getItemInfo(e),n=this._getValues(e,i,t.values);i.forEach(s=>{n.indexOf(s.value)>-1&&s.hide()})}_insertItem(e,t){return h(this,null,function*(){let i=this._findItem(e,t.target);i||(i=t.position==="before"?e.firstElementChild:e.lastElementChild);let n=t.panel;if(i?yield E(i,n,t.position==="before"?"beforeBegin":"afterEnd"):yield E(e,n),this._isAutoClosing(e)){let s=$(n.html).attr("data-value");$(e).find(`[data-value="${s}"] .accordion-collapse`).attr("data-bs-parent","#"+e.id)}})}_removeItem(e,t){let i=this._getItemInfo(e).filter(s=>t.target.indexOf(s.value)>-1),n=Shiny==null?void 0:Shiny.unbindAll;i.forEach(s=>{n&&n(s.item),s.item.remove()})}_updateItem(e,t){return h(this,null,function*(){let i=this._findItem(e,t.target);if(!i)throw new Error(`Unable to find an accordion_panel() with a value of ${t.target}`);if(w(t,"value")&&(i.dataset.value=t.value),w(t,"body")){let s=i.querySelector(".accordion-body");yield E(s,t.body)}let n=i.querySelector(".accordion-header");if(w(t,"title")){let s=n.querySelector(".accordion-title");yield E(s,t.title)}if(w(t,"icon")){let s=n.querySelector(".accordion-button > .accordion-icon");yield E(s,t.icon)}})}_getItemInfo(e){return Array.from(e.querySelectorAll(":scope > .accordion-item")).map(i=>this._getSingleItemInfo(i))}_getSingleItemInfo(e){let t=e.querySelector(".accordion-collapse"),i=()=>$(t).hasClass("show");return{item:e,value:e.dataset.value,isOpen:i,show:()=>{i()||$(t).collapse("show")},hide:()=>{i()&&$(t).collapse("hide")}}}_getValues(e,t,i){let n=i!==!0?i:t.map(l=>l.value);return this._isAutoClosing(e)&&(n=n.slice(n.length-1,n.length)),n}_findItem(e,t){return e.querySelector(`[data-value="${t}"]`)}_isAutoClosing(e){return e.classList.contains("autoclose")}};y(R,"accordion")});var S,z=f(()=>{"use strict";S=class{constructor(){this.resizeObserverEntries=[],this.resizeObserver=new ResizeObserver(e=>{let t=new Event("resize");if(window.dispatchEvent(t),!window.Shiny)return;let i=[];for(let n of e)n.target instanceof HTMLElement&&n.target.querySelector(".shiny-bound-output")&&n.target.querySelectorAll(".shiny-bound-output").forEach(s=>{if(i.includes(s))return;let{binding:l,onResize:d}=$(s).data("shinyOutputBinding");if(!l||!l.resize)return;let o=s.shinyResizeObserver;if(o&&o!==this||(o||(s.shinyResizeObserver=this),d(s),i.push(s),!s.classList.contains("shiny-plot-output")))return;let b=s.querySelector('img:not([width="100%"])');b&&b.setAttribute("width","100%")})})}observe(e){this.resizeObserver.observe(e),this.resizeObserverEntries.push(e)}unobserve(e){let t=this.resizeObserverEntries.indexOf(e);t<0||(this.resizeObserver.unobserve(e),this.resizeObserverEntries.splice(t,1))}flush(){this.resizeObserverEntries.forEach(e=>{document.body.contains(e)||this.unobserve(e)})}}});var I,q=f(()=>{"use strict";I=class{constructor(e,t){this.watching=new Set,this.observer=new MutationObserver(i=>{let n=new Set;for(let{type:s,removedNodes:l}of i)if(s==="childList"&&l.length!==0)for(let d of l)d instanceof HTMLElement&&(d.matches(e)&&n.add(d),d.querySelector(e)&&d.querySelectorAll(e).forEach(o=>n.add(o)));if(n.size!==0)for(let s of n)try{t(s)}catch(l){console.error(l)}})}observe(e){let t=this._flush();if(this.watching.has(e)){if(!t)return}else this.watching.add(e);t?this._restartObserver():this.observer.observe(e,{childList:!0,subtree:!0})}unobserve(e){this.watching.has(e)&&(this.watching.delete(e),this._flush(),this._restartObserver())}_restartObserver(){this.observer.disconnect();for(let e of this.watching)this.observer.observe(e,{childList:!0,subtree:!0})}_flush(){let e=!1,t=Array.from(this.watching);for(let i of t)document.body.contains(i)||(this.watching.delete(i),e=!0);return e}}});var a,g,D=f(()=>{"use strict";L();z();q();a=class{constructor(e){var t;e.removeAttribute(a.attr.ATTR_INIT),(t=e.querySelector(`script[${a.attr.ATTR_INIT}]`))==null||t.remove(),this.card=e,a.instanceMap.set(e,this),a.shinyResizeObserver.observe(this.card),a.cardRemovedObserver.observe(document.body),this._addEventListeners(),this.overlay=this._createOverlay(),this._setShinyInput(),this._exitFullScreenOnEscape=this._exitFullScreenOnEscape.bind(this),this._trapFocusExit=this._trapFocusExit.bind(this)}enterFullScreen(e){var t;e&&e.preventDefault(),this.card.id&&this.overlay.anchor.setAttribute("aria-controls",this.card.id),document.addEventListener("keydown",this._exitFullScreenOnEscape,!1),document.addEventListener("keydown",this._trapFocusExit,!0),this.card.setAttribute(a.attr.ATTR_FULL_SCREEN,"true"),document.body.classList.add(a.attr.CLASS_HAS_FULL_SCREEN),this.card.insertAdjacentElement("beforebegin",this.overlay.container),(!this.card.contains(document.activeElement)||(t=document.activeElement)!=null&&t.classList.contains(a.attr.CLASS_FULL_SCREEN_ENTER))&&(this.card.setAttribute("tabindex","-1"),this.card.focus()),this._emitFullScreenEvent(!0),this._setShinyInput()}exitFullScreen(){document.removeEventListener("keydown",this._exitFullScreenOnEscape,!1),document.removeEventListener("keydown",this._trapFocusExit,!0),this.overlay.container.remove(),this.card.setAttribute(a.attr.ATTR_FULL_SCREEN,"false"),this.card.removeAttribute("tabindex"),document.body.classList.remove(a.attr.CLASS_HAS_FULL_SCREEN),this._emitFullScreenEvent(!1),this._setShinyInput()}_setShinyInput(){if(!this.card.classList.contains(a.attr.CLASS_SHINY_INPUT)||!u)return;if(!u.setInputValue){setTimeout(()=>this._setShinyInput(),0);return}let e=this.card.getAttribute(a.attr.ATTR_FULL_SCREEN);u.setInputValue(this.card.id+"_full_screen",e==="true")}_emitFullScreenEvent(e){let t=new CustomEvent("bslib.card",{bubbles:!0,detail:{fullScreen:e}});this.card.dispatchEvent(t)}_addEventListeners(){let e=this.card.querySelector(`:scope > * > .${a.attr.CLASS_FULL_SCREEN_ENTER}`);e&&e.addEventListener("click",t=>this.enterFullScreen(t))}_exitFullScreenOnEscape(e){if(!(e.target instanceof HTMLElement))return;let t=["select[open]","input[aria-expanded='true']"];e.target.matches(t.join(", "))||e.key==="Escape"&&this.exitFullScreen()}_trapFocusExit(e){if(!(e instanceof KeyboardEvent)||e.key!=="Tab")return;let t=e.target===this.card,i=e.target===this.overlay.anchor,n=this.card.contains(e.target),s=()=>{e.preventDefault(),e.stopImmediatePropagation()};if(!(n||t||i)){s(),this.card.focus();return}let l=U(this.card).filter(A=>!A.classList.contains(a.attr.CLASS_FULL_SCREEN_ENTER));if(!(l.length>0)){s(),this.overlay.anchor.focus();return}if(t)return;let o=l[l.length-1],b=e.target===o;if(i&&e.shiftKey){s(),o.focus();return}if(b&&!e.shiftKey){s(),this.overlay.anchor.focus();return}}_createOverlay(){let e=document.createElement("div");e.id=a.attr.ID_FULL_SCREEN_OVERLAY,e.onclick=this.exitFullScreen.bind(this);let t=this._createOverlayCloseAnchor();return e.appendChild(t),{container:e,anchor:t}}_createOverlayCloseAnchor(){let e=document.createElement("a");return e.classList.add(a.attr.CLASS_FULL_SCREEN_EXIT),e.tabIndex=0,e.setAttribute("aria-expanded","true"),e.setAttribute("aria-label","Close card"),e.setAttribute("role","button"),e.onclick=t=>{this.exitFullScreen(),t.stopPropagation()},e.onkeydown=t=>{(t.key==="Enter"||t.key===" ")&&this.exitFullScreen()},e.innerHTML=this._overlayCloseHtml(),e}_overlayCloseHtml(){return"Close "}static getInstance(e){return a.instanceMap.get(e)}static initializeAllCards(e=!0){if(document.readyState==="loading"){a.onReadyScheduled||(a.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{a.initializeAllCards(!1)}));return}e&&a.shinyResizeObserver.flush();let t=`.${a.attr.CLASS_CARD}[${a.attr.ATTR_INIT}]`;if(!document.querySelector(t))return;document.querySelectorAll(t).forEach(n=>new a(n))}},g=a;g.attr={ATTR_INIT:"data-bslib-card-init",CLASS_CARD:"bslib-card",ATTR_FULL_SCREEN:"data-full-screen",CLASS_HAS_FULL_SCREEN:"bslib-has-full-screen",CLASS_FULL_SCREEN_ENTER:"bslib-full-screen-enter",CLASS_FULL_SCREEN_EXIT:"bslib-full-screen-exit",ID_FULL_SCREEN_OVERLAY:"bslib-full-screen-overlay",CLASS_SHINY_INPUT:"bslib-card-input"},g.shinyResizeObserver=new S,g.cardRemovedObserver=new I(`.${a.attr.CLASS_CARD}`,e=>{let t=a.getInstance(e);t&&t.card.getAttribute(a.attr.ATTR_FULL_SCREEN)==="true"&&t.exitFullScreen()}),g.instanceMap=new WeakMap,g.onReadyScheduled=!1;_("Card",g)});var c,p,F,P=f(()=>{"use strict";L();z();c=class{constructor(e){this.windowSize="";var n;c.instanceMap.set(e,this),this.layout={container:e,main:e.querySelector(":scope > .main"),sidebar:e.querySelector(":scope > .sidebar"),toggle:e.querySelector(":scope > .collapse-toggle")};let t=this.layout.sidebar.querySelector(":scope > .sidebar-content > .accordion");t&&((n=t==null?void 0:t.parentElement)==null||n.classList.add("has-accordion"),t.classList.add("accordion-flush")),this._initSidebarCounters(),this._initSidebarState(),(this._isCollapsible("desktop")||this._isCollapsible("mobile"))&&this._initEventListeners(),c.shinyResizeObserver.observe(this.layout.main),e.removeAttribute("data-bslib-sidebar-init");let i=e.querySelector(":scope > script[data-bslib-sidebar-init]");i&&e.removeChild(i)}get isClosed(){return this.layout.container.classList.contains(c.classes.COLLAPSE)}static getInstance(e){return c.instanceMap.get(e)}_isCollapsible(e="desktop"){let{container:t}=this.layout,i=e==="desktop"?"collapsibleDesktop":"collapsibleMobile",n=t.dataset[i];return n===void 0?!0:n.trim().toLowerCase()!=="false"}static initCollapsibleAll(e=!0){if(document.readyState==="loading"){c.onReadyScheduled||(c.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{c.initCollapsibleAll(!1)}));return}let t=`.${c.classes.LAYOUT}[data-bslib-sidebar-init]`;if(!document.querySelector(t))return;e&&c.shinyResizeObserver.flush(),document.querySelectorAll(t).forEach(n=>new c(n))}_initEventListeners(){var t;let{toggle:e}=this.layout;e.addEventListener("click",i=>{i.preventDefault(),this.toggle("toggle")}),(t=e.querySelector(".collapse-icon"))==null||t.addEventListener("transitionend",()=>this._finalizeState()),!(this._isCollapsible("desktop")&&this._isCollapsible("mobile"))&&window.addEventListener("resize",()=>this._handleWindowResizeEvent())}_initSidebarCounters(){let{container:e}=this.layout,t=`.${c.classes.LAYOUT}> .main > .${c.classes.LAYOUT}:not([data-bslib-sidebar-open="always"])`;if(!(e.querySelector(t)===null))return;function n(o){return o=o?o.parentElement:null,o&&o.classList.contains("main")&&(o=o.parentElement),o&&o.classList.contains(c.classes.LAYOUT)?o:null}let s=[e],l=n(e);for(;l;)s.unshift(l),l=n(l);let d={left:0,right:0};s.forEach(function(o){let A=o.classList.contains("sidebar-right")?d.right++:d.left++;o.style.setProperty("--_js-toggle-count-this-side",A.toString()),o.style.setProperty("--_js-toggle-count-max-side",Math.max(d.right,d.left).toString())})}_getWindowSize(){let{container:e}=this.layout;return window.getComputedStyle(e).getPropertyValue("--bslib-sidebar-js-window-size").trim()}_initialToggleState(){var n,s;let{container:e}=this.layout,t=this.windowSize==="desktop"?"openDesktop":"openMobile",i=(s=(n=e.dataset[t])==null?void 0:n.trim())==null?void 0:s.toLowerCase();return i===void 0||["open","always"].includes(i)?"open":["close","closed"].includes(i)?"close":"open"}_initSidebarState(){this.windowSize=this._getWindowSize();let e=this._initialToggleState();this.toggle(e,!0)}_handleWindowResizeEvent(){let e=this._getWindowSize();!e||e==this.windowSize||this._initSidebarState()}toggle(e,t=!1){typeof e=="undefined"?e="toggle":e==="closed"&&(e="close");let{container:i,sidebar:n}=this.layout,s=this.isClosed;if(["open","close","toggle"].indexOf(e)===-1)throw new Error(`Unknown method ${e}`);if(e==="toggle"&&(e=s?"open":"close"),s&&e==="close"||!s&&e==="open"){t&&this._finalizeState();return}e==="open"&&(n.hidden=!1),i.classList.toggle(c.classes.TRANSITIONING,!t),i.classList.toggle(c.classes.COLLAPSE),t&&this._finalizeState()}_finalizeState(){let{container:e,sidebar:t,toggle:i}=this.layout;e.classList.remove(c.classes.TRANSITIONING),t.hidden=this.isClosed,i.setAttribute("aria-expanded",this.isClosed?"false":"true");let n=new CustomEvent("bslib.sidebar",{bubbles:!0,detail:{open:!this.isClosed}});t.dispatchEvent(n),$(t).trigger("toggleCollapse.sidebarInputBinding"),$(t).trigger(this.isClosed?"hidden":"shown")}},p=c;p.shinyResizeObserver=new S,p.classes={LAYOUT:"bslib-sidebar-layout",COLLAPSE:"sidebar-collapsed",TRANSITIONING:"transitioning"},p.onReadyScheduled=!1,p.instanceMap=new WeakMap;F=class extends m{find(e){return $(e).find(`.${p.classes.LAYOUT} > .bslib-sidebar-input`)}getValue(e){let t=p.getInstance(e.parentElement);return t?!t.isClosed:!1}setValue(e,t){let i=t?"open":"close";this.receiveMessage(e,{method:i})}subscribe(e,t){$(e).on("toggleCollapse.sidebarInputBinding",function(i){t(!0)})}unsubscribe(e){$(e).off(".sidebarInputBinding")}receiveMessage(e,t){let i=p.getInstance(e.parentElement);i&&i.toggle(t.method)}};y(F,"sidebar");_("Sidebar",p)});var T,M,C,x,N,W=f(()=>{"use strict";L();N=class extends m{constructor(){super(...arguments);H(this,C);H(this,T,new WeakMap);H(this,M,new WeakMap)}find(t){return $(t).find(".bslib-task-button")}getValue(t){var i;return{value:(i=v(this,T).get(t))!=null?i:0,autoReset:t.hasAttribute("data-auto-reset")}}getType(){return"bslib.taskbutton"}subscribe(t,i){v(this,M).has(t)&&this.unsubscribe(t);let n=()=>{var s;v(this,T).set(t,((s=v(this,T).get(t))!=null?s:0)+1),i(!0),O(this,C,x).call(this,t,"busy")};v(this,M).set(t,n),t.addEventListener("click",n)}unsubscribe(t){let i=v(this,M).get(t);i&&t.removeEventListener("click",i)}receiveMessage(n,s){return h(this,arguments,function*(t,{state:i}){O(this,C,x).call(this,t,i)})}};T=new WeakMap,M=new WeakMap,C=new WeakSet,x=function(t,i){t.disabled=i==="busy";let n=t.querySelector("bslib-switch-inline");n&&(n.case=i)};y(N,"task-button")});function V(r){if(window.Shiny)for(let[e,t]of Object.entries(r))Shiny.addCustomMessageHandler(e,t)}var j=f(()=>{"use strict"});var Z=X(Y=>{B();D();P();W();L();j();var K={"bslib.toggle-input-binary":r=>h(Y,null,function*(){let e=document.getElementById(r.id);e||console.warn("[bslib.toggle-input-binary] No element found",r);let t=$(e).data("shiny-input-binding");if(!(t instanceof m)){console.warn("[bslib.toggle-input-binary] No input binding found",r);return}let i=r.value;typeof i=="undefined"&&(i=!t.getValue(e)),yield t.receiveMessage(e,{value:i})})};window.Shiny&&V(K);function G(){let r=document.createElement("div");r.innerHTML=` + `,document.body.appendChild(r.children[0])}document.readyState==="complete"?G():document.addEventListener("DOMContentLoaded",G)});Z();})(); + //# sourceMappingURL=components.min.js.map \ No newline at end of file diff --git a/srcjs/bs4Dash-2.3.3/accordions-binding.js b/srcjs/bs4Dash-2.3.4/accordions-binding.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/accordions-binding.js rename to srcjs/bs4Dash-2.3.4/accordions-binding.js diff --git a/srcjs/bs4Dash-2.3.3/cards.js b/srcjs/bs4Dash-2.3.4/cards.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/cards.js rename to srcjs/bs4Dash-2.3.4/cards.js diff --git a/srcjs/bs4Dash-2.3.3/controlbar.js b/srcjs/bs4Dash-2.3.4/controlbar.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/controlbar.js rename to srcjs/bs4Dash-2.3.4/controlbar.js diff --git a/srcjs/bs4Dash-2.3.3/feedbacks.js b/srcjs/bs4Dash-2.3.4/feedbacks.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/feedbacks.js rename to srcjs/bs4Dash-2.3.4/feedbacks.js diff --git a/srcjs/bs4Dash-2.3.3/leftSidebar.js b/srcjs/bs4Dash-2.3.4/leftSidebar.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/leftSidebar.js rename to srcjs/bs4Dash-2.3.4/leftSidebar.js diff --git a/srcjs/bs4Dash-2.3.3/miscellaneous.js b/srcjs/bs4Dash-2.3.4/miscellaneous.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/miscellaneous.js rename to srcjs/bs4Dash-2.3.4/miscellaneous.js diff --git a/srcjs/bs4Dash-2.3.3/navbar.js b/srcjs/bs4Dash-2.3.4/navbar.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/navbar.js rename to srcjs/bs4Dash-2.3.4/navbar.js diff --git a/srcjs/bs4Dash-2.3.3/output-bindings.js b/srcjs/bs4Dash-2.3.4/output-bindings.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/output-bindings.js rename to srcjs/bs4Dash-2.3.4/output-bindings.js diff --git a/srcjs/bs4Dash-2.3.3/pagination-widget.js b/srcjs/bs4Dash-2.3.4/pagination-widget.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/pagination-widget.js rename to srcjs/bs4Dash-2.3.4/pagination-widget.js diff --git a/srcjs/bs4Dash-2.3.3/tabs.js b/srcjs/bs4Dash-2.3.4/tabs.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/tabs.js rename to srcjs/bs4Dash-2.3.4/tabs.js diff --git a/srcjs/bs4Dash-2.3.3/userMessages.js b/srcjs/bs4Dash-2.3.4/userMessages.js similarity index 100% rename from srcjs/bs4Dash-2.3.3/userMessages.js rename to srcjs/bs4Dash-2.3.4/userMessages.js diff --git a/tools/jstools.R b/tools/jstools.R index 87837819..28d2fa65 100644 --- a/tools/jstools.R +++ b/tools/jstools.R @@ -8,12 +8,14 @@ pkg_version <- as.character(utils::packageVersion("bs4Dash")) tmp_old_version <- list.dirs("srcjs", full.names = FALSE, recursive = FALSE) old_version <- strsplit(tmp_old_version, "-")[[1]][2] new_srcjs_folder_name <- sprintf("srcjs/bs4Dash-%s", pkg_version) +outputDir <- sprintf("inst/bs4Dash-%s", pkg_version) if (old_version != pkg_version) { file.rename( file.path("srcjs", tmp_old_version), new_srcjs_folder_name ) + dir.create(outputDir) } # Validate ---------------------------------------------------------------- @@ -26,8 +28,6 @@ bs4DashJS <- list.files( # jshint_file(input = bs4DashJS, options = jshint_options(jquery = TRUE, globals = list("Shiny", "app"))) -outputDir <- sprintf("inst/bs4Dash-%s", pkg_version) - # Concat ----------------------------------------------------------------- # This just aggregates all srcjs files into one big .js file. There is no minifications, ... See next step for terser diff --git a/vignettes/.gitignore b/vignettes/.gitignore index 097b2416..9e2bd63c 100644 --- a/vignettes/.gitignore +++ b/vignettes/.gitignore @@ -1,2 +1,4 @@ *.html *.R + +/.quarto/ diff --git a/vignettes/bs4Dash.Rmd b/vignettes/bs4Dash.Rmd index c68f040f..2107da69 100644 --- a/vignettes/bs4Dash.Rmd +++ b/vignettes/bs4Dash.Rmd @@ -10,6 +10,7 @@ vignette: > --- ```{r, include = FALSE} +library(bslib) knitr::opts_chunk$set( collapse = TRUE, comment = "#>" @@ -83,33 +84,10 @@ Below is a simple app you may build with `{bs4Dash}`. Interestingly, you'll be a the scroll to top button feature if you scroll to the bottom (bottom-right corner), as well as the live theme switcher in the navigation bar that goes from light to dark. This new feature is exclusive to `{bs4Dash}`. -```{r basic-demo-code, eval=FALSE} -library(shiny) -library(bs4Dash) - -shinyApp( - ui = dashboardPage( - header = dashboardHeader( - title = dashboardBrand( - title = "My dashboard", - color = "primary", - href = "https://adminlte.io/themes/v3", - image = "https://adminlte.io/themes/v3/dist/img/AdminLTELogo.png" - ) - ), - sidebar = dashboardSidebar(), - body = dashboardBody( - lapply(getAdminLTEColors(), function(color) { - box(status = color) - }) - ), - controlbar = dashboardControlbar(), - title = "DashboardPage" - ), - server = function(input, output) { } +```{r basic-demo-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/scrollToTop"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-scrollToTop/", TRUE) -``` diff --git a/vignettes/css-preloader.Rmd b/vignettes/css-preloader.Rmd index faa5a19f..dee347a0 100644 --- a/vignettes/css-preloader.Rmd +++ b/vignettes/css-preloader.Rmd @@ -10,6 +10,7 @@ vignette: > --- ```{r setup, include = FALSE} +library(bslib) knitr::opts_chunk$set( collapse = TRUE, comment = "#>" @@ -23,29 +24,10 @@ Pass the argument `preloader` to the `dashboardPage()` function. It expects a li That's all! -```{r waiter-code, eval=FALSE} -library(shiny) -library(bs4Dash) -library(waiter) -shinyApp( - ui = dashboardPage( - preloader = list(html = tagList(spin_1(), "Loading ..."), color = "#3c8dbc"), - header = dashboardHeader(), - sidebar = dashboardSidebar(), - body = dashboardBody( - actionButton("reload", "Reload") - ), - title = "Preloader" - ), - server = function(input, output, session) { - # fake reload - observeEvent(input$reload, { - session$reload() - }) - } +```{r waiter-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/preloader"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-preloader/", TRUE) -``` \ No newline at end of file diff --git a/vignettes/extra-elements.Rmd b/vignettes/extra-elements.Rmd index 1dc0bc73..52c6f26e 100644 --- a/vignettes/extra-elements.Rmd +++ b/vignettes/extra-elements.Rmd @@ -10,6 +10,7 @@ vignette: > --- ```{r setup, include=FALSE} +library(bslib) knitr::opts_chunk$set(echo = TRUE) ``` @@ -22,66 +23,12 @@ expects to contain `accordionItems()`. Importantly, to guaranty the uniqueness o we must provide an __id__ parameter. This parameter allows to programmatically toggle any accordion item, through an `updateAccordion()` function. -```{r accordion-code, eval=FALSE} -library(shiny) -library(bs4Dash) - - shinyApp( - ui = dashboardPage( - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - radioButtons("controller", "Controller", choices = c(1, 2)), - br(), - accordion( - id = "accordion1", - accordionItem( - title = "Accordion 1 Item 1", - status = "danger", - collapsed = TRUE, - "This is some text!" - ), - accordionItem( - title = "Accordion 1 Item 2", - status = "warning", - collapsed = FALSE, - "This is some text!" - ) - ), - accordion( - id = "accordion2", - accordionItem( - title = "Accordion 2 Item 1", - status = "info", - collapsed = TRUE, - "This is some text!" - ), - accordionItem( - title = "Accordion 2 Item 2", - status = "success", - collapsed = FALSE, - "This is some text!" - ) - ) - ), - title = "Accordion" - ), - server = function(input, output, session) { - observeEvent(input$controller, { - updateAccordion(id = "accordion1", selected = input$controller) - }) - - observe(print(input$accordion1)) - - observeEvent(input$accordion1, { - toast(sprintf("You selected accordion N° %s", input$accordion1)) - }) - } - ) -``` - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-accordions/", TRUE) +```{r accordions-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/accordions"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" +) ``` ## User messages @@ -118,99 +65,10 @@ the color is inherited from the `userMessages()` status, while for a received me the color is gray by default. The __text__ argument refers to the message content. It may be simple text, shiny tags or event any combinations of shiny inputs/ouput, as shown in the below example. - -```{r chat-code, eval=FALSE} -shinyApp( - ui = dashboardPage( - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - fluidRow( - actionButton("remove", "Remove message"), - actionButton("add", "Add message"), - actionButton("update", "Update message") - ), - numericInput("index", "Message index:", 1, min = 1, max = 3), - br(), - br(), - userMessages( - width = 6, - status = "danger", - id = "message", - userMessage( - author = "Alexander Pierce", - date = "20 Jan 2:00 pm", - image = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg", - type = "received", - "Is this template really for free? That's unbelievable!" - ), - userMessage( - author = "Sarah Bullock", - date = "23 Jan 2:05 pm", - image = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg", - type = "sent", - "You better believe it!" - ) - ) - ), - title = "user Message" - ), - server = function(input, output, session) { - observeEvent(input$remove, { - updateUserMessages("message", action = "remove", index = input$index) - }) - observeEvent(input$add, { - updateUserMessages( - "message", - action = "add", - content = list( - author = "David", - date = "Now", - image = "https://i.pinimg.com/originals/f1/15/df/f115dfc9cab063597b1221d015996b39.jpg", - type = "received", - text = tagList( - sliderInput( - "obs", - "Number of observations:", - min = 0, - max = 1000, - value = 500 - ), - plotOutput("distPlot") - ) - ) - ) - }) - - output$distPlot <- renderPlot({ - hist(rnorm(input$obs)) - }) - - observeEvent(input$update, { - updateUserMessages( - "message", - action = "update", - index = input$index, - content = list( - text = tagList( - appButton( - inputId = "reload", - label = "Click me!", - icon = icon("sync"), - dashboardBadge(1, color = "danger") - ) - ) - ) - ) - }) - - observeEvent(input$reload, { - toast(title = "Yeah") - }) - } +```{r chat-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/userMessages"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-userMessages/") -``` \ No newline at end of file diff --git a/vignettes/improved-boxes.Rmd b/vignettes/improved-boxes.Rmd index b0f7bf09..fac9ec86 100644 --- a/vignettes/improved-boxes.Rmd +++ b/vignettes/improved-boxes.Rmd @@ -8,6 +8,10 @@ vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- + +```{r setup, include=FALSE} +library(bslib) +``` ## Boxes on Steroids! @@ -24,86 +28,13 @@ is able to provide more interactivity to this component. For instance, you may: To benefit from that feature, one must pass the _id_ parameter and access it on the server side with `input$`. Let's consider an example: - -```{r boxAPI-code, eval=FALSE} -library(shiny) -library(bs4Dash) -ui <- dashboardPage( - title = "Box API", - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - tags$style("body { background-color: ghostwhite}"), - fluidRow( - actionButton("toggle_box", "Toggle Box"), - actionButton("remove_box", "Remove Box", class = "bg-danger"), - actionButton("restore_box", "Restore Box", class = "bg-success"), - actionButton("update_box", "Update Box", class = "bg-primary") - ), - br(), - box( - title = textOutput("box_state"), - "Box body", - id = "mybox", - collapsible = TRUE, - closable = TRUE, - plotOutput("plot") - ) - ) -) - -server <- function(input, output, session) { - output$plot <- renderPlot({ - req(!input$mybox$collapsed) - plot(rnorm(200)) - }) - - output$box_state <- renderText({ - state <- if (input$mybox$collapsed) "collapsed" else "uncollapsed" - paste("My box is", state) - }) - - observeEvent(input$toggle_box, { - updateBox("mybox", action = "toggle") - }) - observeEvent(input$remove_box, { - updateBox("mybox", action = "remove") - }) - - observeEvent(input$restore_box, { - updateBox("mybox", action = "restore") - }) - - observeEvent(input$update_box, { - updateBox( - "mybox", - action = "update", - options = list( - title = h2("New title", dashboardBadge(1, color = "primary")), - status = "danger", - solidHeader = TRUE, - width = 4 - ) - ) - }) - - observeEvent(input$mybox$visible, { - collapsed <- if (input$mybox$collapsed) "collapsed" else "uncollapsed" - visible <- if (input$mybox$visible) "visible" else "hidden" - message <- paste("My box is", collapsed, "and", visible) - toast( - title = message, - options = list( - autohide = TRUE, - class = "bg-pink", - position = "topRight" - ) - ) - }) -} - -shinyApp(ui, server) +```{r boxAPI-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/box-api"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" +) ``` We call the `updateBox()` function, specifying the action to accomplish: @@ -116,10 +47,6 @@ We call the `updateBox()` function, specifying the action to accomplish: Knowing the state of a box significantly opens new possibilities within the application, thereby increasing interactivity. If you want to know more about the underlying mechanisms, have a look at the box widget [documentation](https://adminlte.io/docs/3.1//javascript/card-widget.html). -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-box-api/", deps = TRUE) -``` - ### Box components With `{bs4Dash}`, you may embed labels, a sidebar and dropdown menus in the box header. @@ -139,102 +66,30 @@ do not want to show in the box, while the box body generally contains visualizat the latter displayed on the very right side of the box header, as depicted in Figure \@ref(fig:boxTools). Below is an example showing how to set up the sidebar and toggle it. -```{r boxSidebar-code, eval=FALSE} -shinyApp( - ui = dashboardPage( - header = dashboardHeader(), - body = dashboardBody( - box( - title = "Update box sidebar", - closable = TRUE, - width = 12, - height = "500px", - solidHeader = FALSE, - collapsible = TRUE, - actionButton("update", "Toggle card sidebar"), - sidebar = boxSidebar( - id = "mycardsidebar", - sliderInput( - "obs", - "Number of observations:", - min = 0, - max = 1000, - value = 500 - ) - ), - plotOutput("distPlot") - ) - ), - sidebar = dashboardSidebar() - ), - server = function(input, output, session) { - observe(print(input$mycardsidebar)) - - output$distPlot <- renderPlot({ - hist(rnorm(input$obs)) - }) - - observeEvent(input$update, { - updateBoxSidebar("mycardsidebar") - }) - } +```{r boxSidebar-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/box-sidebar"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` What is the interest of being able to toggle the sidebar on the server? Image you want -to open the sidebar as soon as the user clicks on a specific action button. This is definitely possible. - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-box-sidebar/") -``` +to open the sidebar as soon as the user clicks on a specific action button. #### Box Dropdown `boxDropdown()` is a super powerful tool since all dropdown items may behave like action buttons. This feature allows to seamlessly add interactivity to the box component and gather features in one place. In the example below, clicking on the first item triggers a `toast()`. -```{r boxDropdown-code, eval=FALSE} -shinyApp( - ui = dashboardPage( - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - box( - title = "Closable Box with dropdown", - closable = TRUE, - width = 12, - status = "warning", - solidHeader = FALSE, - collapsible = TRUE, - dropdownMenu = boxDropdown( - boxDropdownItem("Click me", id = "dropdownItem", icon = icon("heart")), - boxDropdownItem("item 2", href = "https://www.google.com/"), - dropdownDivider(), - boxDropdownItem("item 3", icon = icon("th")) - ), - "My box" - ) - ) - ), - server = function(input, output) { - observeEvent(input$dropdownItem, { - toast( - title = "Hi!", - options = list( - autohide = TRUE, - class = "bg-pink", - position = "topRight" - ) - ) - }) - } +```{r boxDropdown-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/box-dropdown"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-box-dropdown/") -``` - ### Other Boxes `{bs4Dash}` provides more box components to be able to adapt to various situations. What if you wanted to create a box with comments, with social content? @@ -262,59 +117,14 @@ userDescription( ``` `userBox()` is also entirely updatable from the server side, as it is built on top the `box()` function: - -```{r userBox-code, eval=FALSE} -shinyApp( - ui = dashboardPage( - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - actionButton("update_box", "Update"), - userBox( - id = "userbox", - title = userDescription( - title = "Nadia Carmichael", - subtitle = "lead Developer", - type = 2, - image = "https://adminlte.io/themes/AdminLTE/dist/img/user7-128x128.jpg", - ), - status = "primary", - gradient = TRUE, - background = "primary", - boxToolSize = "xl", - "Some text here!", - footer = "The footer here!" - ) - ), - title = "userBox" - ), - server = function(input, output) { - observeEvent(input$update_box, { - updateBox( - "userbox", - action = "update", - options = list( - title = userDescription( - title = "Jean Box", - subtitle = "Developer", - type = 1, - image = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg", - ), - status = "danger", - background = NULL, - solidHeader = FALSE, - width = 4 - ) - ) - }) - } +```{r userBox-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/userBox"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-userBox/") -``` - #### socialBox A `socialBox()` is dedicated to contain events, comments, anything related to people. @@ -334,86 +144,10 @@ Right now, there is no programmatic way (understand no __update__ function is av will obviously fill this gap. The app below shows a combination of multiple elements in a `socialBox()`: - -```{r, eval=FALSE} -shinyApp( - ui = dashboardPage( - dashboardHeader(), - dashboardSidebar(), - dashboardBody( - socialBox( - id = "socialbox", - title = userBlock( - image = "https://adminlte.io/themes/AdminLTE/dist/img/user4-128x128.jpg", - title = "Social Box", - subtitle = "example-01.05.2018" - ), - actionButton("update_box", "Refresh"), - "Some text here!", - br(), br(), - tabsetPanel( - tabPanel( - "News", - attachmentBlock( - image = "https://www.sammobile.com/wp-content/uploads/2017/11/Camel.png", - title = "Test", - href = "https://google.com", - "This is the content" - ) - ), - tabPanel( - "Messages", - userMessages( - width = 12, - status = "danger", - userMessage( - author = "Alexander Pierce", - date = "20 Jan 2:00 pm", - image = "https://adminlte.io/themes/AdminLTE/dist/img/user1-128x128.jpg", - type = "received", - "Is this template really for free? That's unbelievable!" - ), - userMessage( - author = "Sarah Bullock", - date = "23 Jan 2:05 pm", - image = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg", - type = "sent", - "You better believe it!" - ) - ) - ) - ), - lapply(X = 1:10, FUN = function(i) { - boxComment( - image = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg", - title = paste("Comment", i), - date = "01.05.2018", - paste0("The ", i, "-th comment") - ) - }), - footer = "The footer here!" - ) - ), - title = "Social Box" - ), - server = function(input, output) { - observeEvent(input$update_box, { - updateBox( - "socialbox", - action = "update", - options = list( - title = userBlock( - image = "https://adminlte.io/themes/AdminLTE/dist/img/user3-128x128.jpg", - title = "Social Box updated", - subtitle = "today" - ) - ) - ) - }) - } +```{r socialBox-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/socialBox"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` - -```{r, echo=FALSE} -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-socialBox/") -``` \ No newline at end of file diff --git a/vignettes/more-skins.Rmd b/vignettes/more-skins.Rmd index 5287d74e..a13db4b5 100644 --- a/vignettes/more-skins.Rmd +++ b/vignettes/more-skins.Rmd @@ -11,6 +11,7 @@ vignette: > ```{r setup, include=FALSE} library(shiny) +library(bslib) knitr::opts_chunk$set( collapse = TRUE, comment = "#>" @@ -23,39 +24,14 @@ knitr::opts_chunk$set( allowing the end user to change the app skin. There are 20 unique colors with 2 versions, light or dark. Note that the `dashboardControlbar()` is the perfect place to host the `skinSelector()`. -```{r skinSelector-code, eval=FALSE} -library(shiny) -library(bs4Dash) -shinyApp( - ui = dashboardPage( - header = dashboardHeader(), - sidebar = dashboardSidebar( - sidebarMenu( - menuItem( - text = "Item 1" - ), - menuItem( - text = "Item 2" - ) - ) - ), - body = dashboardBody(), - controlbar = dashboardControlbar( - collapsed = FALSE, - div(class = "p-3", skinSelector()), - pinned = TRUE - ), - title = "Skin Selector" - ), - server = function(input, output) { } +```{r skinSelector-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/skinSelector"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` -```{r, echo=FALSE} -# App output -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-skinSelector/", TRUE) -``` - ## Fresh [`{fresh}`](https://dreamrs.github.io/fresh/index.html) is developed by the [dreamRs](https://www.dreamrs.fr/) team. It is built on top of `{sass}`, which @@ -71,92 +47,10 @@ the sidebar component, `bs4dash_layout()` controls the main background color, `b contrast and `bs4dash_vars()` offers deeper customization (navbar, ...). The fresh theme below is based on some dark theme color palettes. -```{r fresh-code, eval=FALSE} -library(fresh) -# create the theme with a cyberpunk color palette -theme <- create_theme( - bs4dash_vars( - navbar_light_color = "#bec5cb", - navbar_light_active_color = "#FFF", - navbar_light_hover_color = "#FFF" - ), - bs4dash_yiq( - contrasted_threshold = 10, - text_dark = "#FFF", - text_light = "#272c30" - ), - bs4dash_layout( - main_bg = "#353c42" - ), - bs4dash_sidebar_light( - bg = "#272c30", - color = "#bec5cb", - hover_color = "#FFF", - submenu_bg = "#272c30", - submenu_color = "#FFF", - submenu_hover_color = "#FFF" - ), - bs4dash_status( - primary = "#5E81AC", danger = "#BF616A", light = "#272c30" - ), - bs4dash_color( - gray_900 = "#FFF", white = "#272c30" - ) -) - -# create tribble for box global config -box_config <- tibble::tribble( - ~background, ~labelStatus, - "danger", "warning", - "purple", "success", - "success", "primary", - "warning", "danger", - "fuchsia", "info" -) - -# box factory function -box_factory <- function(background, labelStatus) { - box( - title = "Cyberpunk Box", - collapsible = TRUE, - background = background, - height = "200px", - label = boxLabel(1, labelStatus) - ) -} - -# pmap magic -boxes <- purrr::pmap(box_config, box_factory) - -shinyApp( - ui = dashboardPage( - freshTheme = theme, - header = dashboardHeader( - leftUi = dropdownMenu( - type = "messages", - badgeStatus = "success", - messageItem( - from = "Support Team", - message = "This is the content of a message.", - time = "5 mins" - ), - messageItem( - from = "Support Team", - message = "This is the content of another message.", - time = "2 hours" - ) - ) - ), - sidebar = dashboardSidebar(), - body = dashboardBody(boxes), - controlbar = dashboardControlbar(), - title = "Fresh theming" - ), - server = function(input, output) { } +```{r fresh-code, eval=TRUE, echo=FALSE} +card( + bs4Dash:::create_link_iframe(bs4Dash:::shinylive_links["inst/examples/vignettes-demos/fresh-theming"]), + full_screen = TRUE, + style = "margin: 0 auto; float: none;" ) ``` - -```{r, echo=FALSE} -# App output -bs4Dash:::app_container("https://dgranjon.shinyapps.io/bs4Dash-fresh-theming/") -``` \ No newline at end of file