diff --git a/.Rbuildignore b/.Rbuildignore
index 1fa2852..44b1be9 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -8,3 +8,4 @@
^LICENSE\.md$
^.vscode$
^index\.md$
+^README\.Rmd$
diff --git a/DESCRIPTION b/DESCRIPTION
index 6522f45..01aa5e1 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -22,3 +22,5 @@ Imports:
shiny,
magrittr,
httpuv
+Depends:
+ R (>= 2.10)
diff --git a/R/sysdata.rda b/R/sysdata.rda
new file mode 100644
index 0000000..d7c4acf
Binary files /dev/null and b/R/sysdata.rda differ
diff --git a/R/utils-shiny.R b/R/utils-shiny.R
index 0ff6f9d..e57187e 100644
--- a/R/utils-shiny.R
+++ b/R/utils-shiny.R
@@ -468,3 +468,16 @@ buildTabItem <- function (index, tabsetId, foundSelected, tabs = NULL, divTag =
}
return(list(liTag = liTag, divTag = divTag))
}
+
+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.Rmd b/README.Rmd
new file mode 100644
index 0000000..3e5709b
--- /dev/null
+++ b/README.Rmd
@@ -0,0 +1,44 @@
+---
+output: github_document
+---
+
+
+
+# shiny386
+
+
+[](https://CRAN.R-project.org/package=shiny386)
+[](https://www.tidyverse.org/lifecycle/#experimental)
+[](https://github.com/RinteRface/shiny386/actions)
+
+
+The goal of shiny386 is to provide an old school Bootstrap 4 template for Shiny. It is built on top of the [Bootstrap 386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML template.
+
+## Installation
+
+You can install the released version of shiny386 from Github with:
+
+``` r
+pak::paks("RinteRface/shiny386")
+```
+
+## Example
+
+This is a basic example which shows you how to solve a common problem:
+
+``` r
+library(shiny)
+library(shiny386)
+ui <- page_386(
+ card_386(
+ title = "My card",
+ "This is my card",
+ br(),
+ card_link_386(href = "https://www.google.com", "More"),
+ footer = "Card footer"
+ )
+)
+
+server <- function(input, output, session) {}
+shinyApp(ui, server)
+```
diff --git a/README.md b/README.md
index 2acd21c..91cfe03 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,29 @@
+
+
# shiny386
-[](https://CRAN.R-project.org/package=shiny386)
-[](https://www.tidyverse.org/lifecycle/#experimental)
-[](https://github.com/RinteRface/shiny386/actions)
+
+[](https://CRAN.R-project.org/package=shiny386)
+[](https://www.tidyverse.org/lifecycle/#experimental)
+[](https://github.com/RinteRface/shiny386/actions)
-The goal of shiny386 is to provide an old school Bootstrap 4 template for Shiny. It is built on top of the [Bootstrap 386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML template.
+The goal of shiny386 is to provide an old school Bootstrap 4 template
+for Shiny. It is built on top of the [Bootstrap
+386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML
+template.
## Installation
You can install the released version of shiny386 from Github with:
``` r
-remotes::install_github("RinteRface/shiny386")
+pak::paks("RinteRface/shiny386")
```
## Example
@@ -37,4 +46,3 @@ ui <- page_386(
server <- function(input, output, session) {}
shinyApp(ui, server)
```
-
diff --git a/_pkgdown.yml b/_pkgdown.yml
index e69de29..604e5ea 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -0,0 +1,3 @@
+template:
+ bootstrap: 5
+url: https://shiny386.rinterface.com/
diff --git a/index.Rmd b/index.Rmd
new file mode 100644
index 0000000..a93b577
--- /dev/null
+++ b/index.Rmd
@@ -0,0 +1,60 @@
+---
+output: github_document
+always_allow_html: true
+---
+
+```{r setup, include=FALSE}
+library(bslib)
+knitr::opts_chunk$set(echo = TRUE)
+```
+
+# shiny386
+
+
+[](https://CRAN.R-project.org/package=shiny386)
+[](https://www.tidyverse.org/lifecycle/#experimental)
+[](https://github.com/RinteRface/shiny386/actions)
+
+
+The goal of shiny386 is to provide an old school Bootstrap 4 template for Shiny. It is built on top of the [Bootstrap 386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML template.
+
+## Installation
+
+You can install the released version of shiny386 from Github with:
+
+``` r
+pak::pak("RinteRface/shiny386")
+```
+
+## Demo
+
+```{r showcase-code, eval=TRUE, echo=FALSE}
+card(
+ shiny386:::create_link_iframe(shiny386:::shinylive_links["inst/examples/shinylive/basic"]),
+ full_screen = TRUE,
+ style = "margin: 0 auto; float: none;"
+)
+```
+
+The original app may be found [here](https://shiny.rstudio.com/gallery/bus-dashboard.html)
+
+## Example
+
+This is a basic example which shows you how to solve a common problem:
+
+``` r
+library(shiny)
+library(shiny386)
+ui <- page_386(
+ card_386(
+ title = "My card",
+ "This is my card",
+ br(),
+ card_link_386(href = "https://www.google.com", "More"),
+ footer = "Card footer"
+ )
+)
+
+server <- function(input, output, session) {}
+shinyApp(ui, server)
+```
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f6f6839
--- /dev/null
+++ b/index.html
@@ -0,0 +1,649 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
shiny386
+
+
+
+
+
+
The goal of shiny386 is to provide an old school Bootstrap 4 template
+for Shiny. It is built on top of the Bootstrap
+386 HTML template.
+
Installation
+
You can install the released version of shiny386 from Github
+with:
+
+
+
diff --git a/index.md b/index.md
index 79f3b22..77163a7 100644
--- a/index.md
+++ b/index.md
@@ -2,26 +2,43 @@
# shiny386
-[](https://CRAN.R-project.org/package=shiny386)
-[](https://www.tidyverse.org/lifecycle/#experimental)
-[](https://github.com/RinteRface/shiny386/actions)
+
+[](https://CRAN.R-project.org/package=shiny386)
+[](https://www.tidyverse.org/lifecycle/#experimental)
+[](https://github.com/RinteRface/shiny386/actions)
-The goal of shiny386 is to provide an old school Bootstrap 4 template for Shiny. It is built on top of the [Bootstrap 386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML template.
+The goal of shiny386 is to provide an old school Bootstrap 4 template
+for Shiny. It is built on top of the [Bootstrap
+386](http://kristopolous.github.io/BOOTSTRA.386/demo.html) HTML
+template.
## Installation
You can install the released version of shiny386 from Github with:
``` r
-remotes::install_github("RinteRface/shiny386")
+pak::pak("RinteRface/shiny386")
```
## Demo
-
-
-The original app may be found [here](https://shiny.rstudio.com/gallery/bus-dashboard.html)
+
+
+
+
+
+Expand
+
+
+
+
+
+The original app may be found
+[here](https://shiny.rstudio.com/gallery/bus-dashboard.html)
## Example
diff --git a/inst/examples/shinylive/basic/app.R b/inst/examples/shinylive/basic/app.R
new file mode 100644
index 0000000..8e38a8a
--- /dev/null
+++ b/inst/examples/shinylive/basic/app.R
@@ -0,0 +1,19 @@
+webr::install(
+ "shiny386",
+ repos = c("https://rinterface.github.io/rinterface-wasm-cran/", "https://repo.r-wasm.org")
+)
+
+library(shiny)
+library(shiny386)
+ui <- page_386(
+ card_386(
+ title = "My card",
+ "This is my card",
+ br(),
+ card_link_386(href = "https://www.google.com", "More"),
+ footer = "Card footer"
+ )
+)
+
+server <- function(input, output, session) {}
+shinyApp(ui, server)
\ No newline at end of file
diff --git a/inst/shinylive/tools.R b/inst/shinylive/tools.R
new file mode 100644
index 0000000..d7b6b8f
--- /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/shinylive")
+}
+
+shinylive_links <- create_vignettes_links()
+usethis::use_data(shinylive_links, internal = TRUE, overwrite = TRUE)
\ No newline at end of file
diff --git a/pkgdown/extra.css b/pkgdown/extra.css
new file mode 100644
index 0000000..2a7e185
--- /dev/null
+++ b/pkgdown/extra.css
@@ -0,0 +1,23 @@
+/* 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;
+}
\ No newline at end of file
diff --git a/pkgdown/extra.js b/pkgdown/extra.js
new file mode 100644
index 0000000..879ceb6
--- /dev/null
+++ b/pkgdown/extra.js
@@ -0,0 +1,804 @@
+/*! bslib 0.8.0 | (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, s) => {
+ var n = o => {
+ try {
+ d(t.next(o))
+ } catch (b) {
+ s(b)
+ }
+ }
+ , l = o => {
+ try {
+ d(t.throw(o))
+ } catch (b) {
+ s(b)
+ }
+ }
+ , d = o => o.done ? i(o.value) : Promise.resolve(o.value).then(n, 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(n => n + t.join(""))
+ , s = r.querySelectorAll(i.join(", "));
+ return Array.from(s)
+ }
+ 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(s => s.isOpen()).map(s => s.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)
+ , s = this._getValues(e, i, t.values);
+ i.forEach(n => {
+ s.indexOf(n.value) > -1 ? n.show() : n.hide()
+ }
+ )
+ }
+ _openItems(e, t) {
+ let i = this._getItemInfo(e)
+ , s = this._getValues(e, i, t.values);
+ i.forEach(n => {
+ s.indexOf(n.value) > -1 && n.show()
+ }
+ )
+ }
+ _closeItems(e, t) {
+ let i = this._getItemInfo(e)
+ , s = this._getValues(e, i, t.values);
+ i.forEach(n => {
+ s.indexOf(n.value) > -1 && n.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 s = t.panel;
+ if (i ? yield E(i, s, t.position === "before" ? "beforeBegin" : "afterEnd") : yield E(e, s),
+ this._isAutoClosing(e)) {
+ let n = $(s.html).attr("data-value");
+ $(e).find(`[data-value="${n}"] .accordion-collapse`).attr("data-bs-parent", "#" + e.id)
+ }
+ })
+ }
+ _removeItem(e, t) {
+ var n;
+ let i = this._getItemInfo(e).filter(l => t.target.indexOf(l.value) > -1)
+ , s = (n = window.Shiny) == null ? void 0 : n.unbindAll;
+ i.forEach(l => {
+ s && s(l.item),
+ l.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 n = i.querySelector(".accordion-body");
+ yield E(n, t.body)
+ }
+ let s = i.querySelector(".accordion-header");
+ if (w(t, "title")) {
+ let n = s.querySelector(".accordion-title");
+ yield E(n, t.title)
+ }
+ if (w(t, "icon")) {
+ let n = s.querySelector(".accordion-button > .accordion-icon");
+ yield E(n, 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 s = i !== !0 ? i : t.map(l => l.value);
+ return this._isAutoClosing(e) && (s = s.slice(s.length - 1, s.length)),
+ s
+ }
+ _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 s of e)
+ s.target instanceof HTMLElement && s.target.querySelector(".shiny-bound-output") && s.target.querySelectorAll(".shiny-bound-output").forEach(n => {
+ if (i.includes(n))
+ return;
+ let {binding: l, onResize: d} = $(n).data("shinyOutputBinding");
+ if (!l || !l.resize)
+ return;
+ let o = n.shinyResizeObserver;
+ if (o && o !== this || (o || (n.shinyResizeObserver = this),
+ d(n),
+ i.push(n),
+ !n.classList.contains("shiny-plot-output")))
+ return;
+ let b = n.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 s = new Set;
+ for (let {type: n, removedNodes: l} of i)
+ if (n === "childList" && l.length !== 0)
+ for (let d of l)
+ d instanceof HTMLElement && (d.matches(e) && s.add(d),
+ d.querySelector(e) && d.querySelectorAll(e).forEach(o => s.add(o)));
+ if (s.size !== 0)
+ for (let n of s)
+ try {
+ t(n)
+ } 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
+ , s = this.card.contains(e.target)
+ , n = () => {
+ e.preventDefault(),
+ e.stopImmediatePropagation()
+ }
+ ;
+ if (!(s || t || i)) {
+ n(),
+ this.card.focus();
+ return
+ }
+ let l = U(this.card).filter(A => !A.classList.contains(a.attr.CLASS_FULL_SCREEN_ENTER));
+ if (!(l.length > 0)) {
+ n(),
+ this.overlay.anchor.focus();
+ return
+ }
+ if (t)
+ return;
+ let o = l[l.length - 1]
+ , b = e.target === o;
+ if (i && e.shiftKey) {
+ n(),
+ o.focus();
+ return
+ }
+ if (b && !e.shiftKey) {
+ n(),
+ 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(s => new a(s))
+ }
+ }
+ ,
+ 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 s;
+ 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 && ((s = t == null ? void 0 : t.parentElement) == null || s.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"
+ , s = t.dataset[i];
+ return s === void 0 ? !0 : s.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(s => new c(s))
+ }
+ _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 s(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 n = [e]
+ , l = s(e);
+ for (; l; )
+ n.unshift(l),
+ l = s(l);
+ let d = {
+ left: 0,
+ right: 0
+ };
+ n.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 s, n;
+ let {container: e} = this.layout
+ , t = this.windowSize === "desktop" ? "openDesktop" : "openMobile"
+ , i = (n = (s = e.dataset[t]) == null ? void 0 : s.trim()) == null ? void 0 : n.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: s} = this.layout
+ , n = this.isClosed;
+ if (["open", "close", "toggle"].indexOf(e) === -1)
+ throw new Error(`Unknown method ${e}`);
+ if (e === "toggle" && (e = n ? "open" : "close"),
+ n && e === "close" || !n && e === "open") {
+ t && this._finalizeState();
+ return
+ }
+ e === "open" && (s.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 s = new CustomEvent("bslib.sidebar",{
+ bubbles: !0,
+ detail: {
+ open: !this.isClosed
+ }
+ });
+ t.dispatchEvent(s),
+ $(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 s = () => {
+ var n;
+ v(this, T).set(t, ((n = v(this, T).get(t)) != null ? n : 0) + 1),
+ i(!0),
+ O(this, C, x).call(this, t, "busy")
+ }
+ ;
+ v(this, M).set(t, s),
+ t.addEventListener("click", s)
+ }
+ unsubscribe(t) {
+ let i = v(this, M).get(t);
+ i && t.removeEventListener("click", i)
+ }
+ receiveMessage(s, n) {
+ 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 s = t.querySelector("bslib-switch-inline");
+ s && (s.case = i)
+ }
+ ;
+ y(N, "task-button")
+ }
+ );
+ function V(r) {
+ if (window.Shiny)
+ for (let[e,t] of Object.entries(r))
+ window.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