diff --git a/NEWS.md b/NEWS.md
index f8e65a60c..d6ff739aa 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -31,6 +31,8 @@
* Improved the style and appearance of the button to enter full screen in `card()`s and `value_box()`es to better adapt to Bootstrap's dark mode. (#780)
+* `layout_sidebar()` received a new design. The button to collapse and expand the sidebar now appears at the top edge of the sidebar, and we now use the [arrow-bar-left](https://icons.getbootstrap.com/icons/arrow-bar-left/) icon instead of [chevron-left](https://icons.getbootstrap.com/icons/chevron-left/). On mobile devices, the sidebar now fills the `layout_sidebar()` area as an overlay, rather than expanding from above the main content area. **Note** the `max_mobile_height` argument of `sidebar()` determines the maximum height of the sidebar area on mobile, but it now only applies when `open = "always"`. (#798)
+
## Bug fixes
* `toggle_switch()` now works correctly when called from within a Shiny module. `update_switch()` worked as expected, but `toggle_switch()` didn't apply the module's namespace to the `id` of the switch to be updated. (#769)
diff --git a/R/sidebar.R b/R/sidebar.R
index f49377a2b..d8b264139 100644
--- a/R/sidebar.R
+++ b/R/sidebar.R
@@ -50,10 +50,11 @@
#' color, e.g. setting `bg` chooses an appropriate `fg` color.
#' @param class CSS classes for the sidebar container element, in addition to
#' the fixed `.sidebar` class.
-#' @param max_height_mobile The maximum height of the horizontal sidebar when
-#' viewed on mobile devices. The default is `250px` unless the sidebar is
-#' included in a [layout_sidebar()] with a specified height, in which case
-#' the default is to take up no more than 50% of the layout container.
+#' @param max_height_mobile A [CSS length unit][htmltools::validateCssUnit()]
+#' defining the maximum height of the horizontal sidebar when viewed on mobile
+#' devices. Only applies to always-open sidebars that use `open = "always"`,
+#' where by default the sidebar container is placed below the main content
+#' container on mobile devices.
#' @param gap A [CSS length unit][htmltools::validateCssUnit()] defining the
#' vertical `gap` (i.e., spacing) between adjacent elements provided to `...`.
#' @param padding Padding within the sidebar itself. This can be a numeric
@@ -91,6 +92,11 @@ sidebar <- function(
open <- rlang::arg_match(open)
+ if (!is.null(max_height_mobile) && open != "always") {
+ rlang::warn('The `max_height_mobile` argument only applies to when `open = "always"`.')
+ max_height_mobile <- NULL
+ }
+
if (!is.null(id)) {
if (length(id) != 1 || is.na(id) || !nzchar(id)) {
rlang::abort("`id` must be a non-empty, length-1 character string or `NULL`.")
@@ -210,8 +216,6 @@ layout_sidebar <- function(
class = "main",
class = if (fillable) "bslib-gap-spacing",
style = css(
- background_color = bg,
- color = fg,
padding = validateCssPadding(padding),
gap = validateCssUnit(gap)
),
@@ -237,8 +241,10 @@ layout_sidebar <- function(
`data-bslib-sidebar-border-radius` = if (!is.null(border_radius)) tolower(border_radius),
style = css(
"--bslib-sidebar-width" = sidebar$width,
- "--bslib-sidebar-bg" = if (!is.null(sidebar$color$bg)) sidebar$color$bg,
- "--bslib-sidebar-fg" = if (!is.null(sidebar$color$fg)) sidebar$color$fg,
+ "--bslib-sidebar-bg" = sidebar$color$bg,
+ "--bslib-sidebar-fg" = sidebar$color$fg,
+ "--bslib-sidebar-main-fg" = fg,
+ "--bslib-sidebar-main-bg" = bg,
"--bs-card-border-color" = border_color,
height = validateCssUnit(height),
"--bslib-sidebar-max-height-mobile" = max_height_mobile
@@ -291,10 +297,10 @@ sidebar_toggle <- toggle_sidebar
collapse_icon <- function() {
if (!is_installed("bsicons")) {
- icon <- ""
+ icon <- ""
return(HTML(icon))
}
- bsicons::bs_icon("chevron-down", class = "collapse-icon", size = NULL)
+ bsicons::bs_icon("arrow-bar-left", class = "collapse-icon", size = NULL)
}
sidebar_init_js <- function() {
diff --git a/R/sysdata.rda b/R/sysdata.rda
index 5f69d4ab9..ed0482730 100644
Binary files a/R/sysdata.rda and b/R/sysdata.rda differ
diff --git a/inst/components/dist/sidebar/sidebar.css b/inst/components/dist/sidebar/sidebar.css
index 512d57f1f..79e906505 100644
--- a/inst/components/dist/sidebar/sidebar.css
+++ b/inst/components/dist/sidebar/sidebar.css
@@ -1 +1 @@
-.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-collapse-toggle-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-collapse-toggle-transform: 90deg;--bslib-collapse-toggle-right-transform: -90deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:Min(calc(100% - var(--bslib-sidebar-icon-size)), var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media (prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border="false"]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius="false"]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1 / 2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2 / 3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.sidebar{grid-column:1 / 2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;background-color:var(--bslib-sidebar-bg);color:var(--bslib-sidebar-fg)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1 * var(--bslib-sidebar-padding));margin-right:calc(-1 * var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:first-child{margin-top:calc(-1 * var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1 * var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.sidebar-title+.accordion{margin-top:calc(-1rem - var(--bs-card-border-width, var(--bs-border-width)))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.sidebar-title:has(+.accordion){border-bottom:none}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout>.collapse-toggle{grid-row:1 / 2;grid-column:1 / 2;display:inline-flex;align-items:center;position:absolute;right:calc(-1 * var(--bslib-sidebar-icon-size));bottom:calc(var(--bslib-sidebar-padding) + var(--bslib-sidebar-overlap-counter, 0) * calc(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)));border:var(--bslib-collapse-toggle-border);border-left:none;border-radius:0 var(--bs-border-radius) var(--bs-border-radius) 0;padding:7px 0;background-color:var(--bslib-sidebar-bg);color:var(--bslib-sidebar-fg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:0.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotate(var(--bslib-collapse-toggle-transform));transition:transform cubic-bezier(0.68, -0.55, 0.27, 1.55) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) Min(calc(100% - var(--bslib-sidebar-icon-size)), var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1 / 2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2 / 3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2 / 3;left:calc(-1 * var(--bslib-sidebar-icon-size));right:unset;border-radius:var(--bs-border-radius) 0 0 var(--bs-border-radius);border-right:none;border-left:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotate(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: -90deg;--bslib-collapse-toggle-right-transform: 90deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{right:calc(-1 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-1 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media (min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media (max-width: 575.98px){.bslib-sidebar-layout,.bslib-sidebar-layout.sidebar-right{--bslib-sidebar-vert-border: none;--bslib-sidebar-horiz-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-collapse-toggle-transform: -180deg;--bslib-collapse-toggle-right-transform: -180deg;grid-template-columns:1fr !important;grid-template-rows:fit-content(var(--bslib-sidebar-max-height-mobile, auto)) minmax(0, 1fr)}.bslib-sidebar-layout[data-bslib-sidebar-open="desktop"],.bslib-sidebar-layout.sidebar-right[data-bslib-sidebar-open="desktop"]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{grid-row:1 / 2;grid-column:1 / 2;width:100%;border:none;border-bottom:var(--bslib-sidebar-horiz-border);border-radius:0}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-row:2 / 3;grid-column:1 / 2;border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout>.collapse-toggle,.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-row:2 / 3;grid-column:1 / 2;border-top:none !important;border:var(--bslib-collapse-toggle-border);border-radius:0 0 var(--bs-border-radius) var(--bs-border-radius);padding:0 4px}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon,.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transition-duration:calc(var(--bslib-sidebar-transition-duration) * 0.33)}.bslib-sidebar-layout>.collapse-toggle,.bslib-sidebar-layout.sidebar-right>.collapse-toggle,.bslib-sidebar-layout.sidebar-right>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-right>.collapse-toggle{top:calc(-1 * var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-right.sidebar-collapsed>.collapse-toggle{top:0}.bslib-sidebar-layout>.collapse-toggle,.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-right>.collapse-toggle,.bslib-sidebar-layout.sidebar-right.sidebar-right.sidebar-collapsed>.collapse-toggle{right:calc(var(--bslib-sidebar-padding) + var(--bslib-sidebar-counter, 0) * calc(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)));bottom:initial;left:initial}.bslib-sidebar-layout.sidebar-collapsed,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed{--bslib-collapse-toggle-transform: 0deg;--bslib-collapse-toggle-right-transform: 0deg;grid-template-rows:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed>.main,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.main{border-top-left-radius:inherit;border-top-right-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed>.sidebar,.bslib-sidebar-layout.sidebar-right.sidebar-collapsed>.sidebar{border-bottom:none}}
+.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, var(--bs-border-width)) solid var(--bs-card-border-color, var(--bs-border-color-translucent));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, .375rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:Min(calc(100% - var(--bslib-sidebar-icon-size)), var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media (prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border="false"]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius="false"]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1 / 2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2 / 3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1 / 2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1 * var(--bslib-sidebar-padding));margin-right:calc(-1 * var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1 * var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open="always"]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1 / 2;grid-column:1 / 2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem) / 2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:0.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) Min(calc(100% - var(--bslib-sidebar-icon-size)), var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1 / 2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2 / 3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2 / 3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc( var(--bslib-sidebar-overlap-counter, 0) * calc(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding) ) + var(--bslib-sidebar-icon-size, 1rem) / 2);right:calc(-2.5 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media (min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media (max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open="desktop"]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1 / 3}.bslib-sidebar-layout[data-bslib-sidebar-open="always"]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open="always"]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open="always"]).sidebar-collapsed>.main{opacity:1}}
diff --git a/inst/components/dist/sidebar/sidebar.js b/inst/components/dist/sidebar/sidebar.js
index af18ddb40..79437ee05 100644
--- a/inst/components/dist/sidebar/sidebar.js
+++ b/inst/components/dist/sidebar/sidebar.js
@@ -123,6 +123,7 @@
* @param {HTMLElement} container
*/
constructor(container) {
+ var _a;
_Sidebar.instanceMap.set(container, this);
this.layout = {
container,
@@ -136,6 +137,7 @@
":scope > .sidebar-content > .accordion"
);
if (sideAccordion) {
+ (_a = sideAccordion == null ? void 0 : sideAccordion.parentElement) == null ? void 0 : _a.classList.add("has-accordion");
sideAccordion.classList.add("accordion-flush");
}
if (this.layout.toggle) {
diff --git a/inst/components/dist/sidebar/sidebar.js.map b/inst/components/dist/sidebar/sidebar.js.map
index 922ebdfcc..7e5910ad5 100644
--- a/inst/components/dist/sidebar/sidebar.js.map
+++ b/inst/components/dist/sidebar/sidebar.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../../srcts/src/components/_utils.ts", "../../../../srcts/src/components/_shinyResizeObserver.ts", "../../../../srcts/src/components/sidebar.ts"],
- "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import { InputBinding, registerBinding } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n/**\n * Methods for programmatically toggling the state of the sidebar. These methods\n * describe the desired state of the sidebar: `\"close\"` and `\"open\"` transition\n * the sidebar to the desired state, unless the sidebar is already in that\n * state. `\"toggle\"` transitions the sidebar to the state opposite of its\n * current state.\n * @typedef {SidebarToggleMethod}\n */\ntype SidebarToggleMethod = \"close\" | \"open\" | \"toggle\";\n\n/**\n * Data received by the input binding's `receiveMessage` method.\n * @typedef {SidebarMessageData}\n */\ntype SidebarMessageData = {\n method: SidebarToggleMethod;\n};\n\n/**\n * The DOM elements that make up the sidebar. `main`, `sidebar`, and `toggle`\n * are all direct children of `container` (in that order).\n * @interface SidebarComponents\n * @typedef {SidebarComponents}\n */\ninterface SidebarComponents {\n /**\n * The `layout_sidebar()` parent container, with class\n * `Sidebar.classes.LAYOUT`.\n * @type {HTMLElement}\n */\n container: HTMLElement;\n /**\n * The main content area of the sidebar layout.\n * @type {HTMLElement}\n */\n main: HTMLElement;\n /**\n * The sidebar container of the sidebar layout.\n * @type {HTMLElement}\n */\n sidebar: HTMLElement;\n /**\n * The toggle button that is used to toggle the sidebar state.\n * @type {HTMLElement}\n */\n toggle: HTMLElement;\n}\n\n/**\n * The bslib sidebar component class. This class is only used for collapsible\n * sidebars.\n *\n * @class Sidebar\n * @typedef {Sidebar}\n */\nclass Sidebar {\n /**\n * The DOM elements that make up the sidebar, see `SidebarComponents`.\n * @private\n * @type {SidebarComponents}\n */\n private layout: SidebarComponents;\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in the main\n * content areas of the sidebar resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a collapsible bslib Sidebar.\n * @constructor\n * @param {HTMLElement} container\n */\n constructor(container: HTMLElement) {\n Sidebar.instanceMap.set(container, this);\n this.layout = {\n container,\n main: container.querySelector(\":scope > .main\") as HTMLElement,\n sidebar: container.querySelector(\":scope > .sidebar\") as HTMLElement,\n toggle: container.querySelector(\n \":scope > .collapse-toggle\"\n ) as HTMLElement,\n } as SidebarComponents;\n\n const sideAccordion = this.layout.sidebar.querySelector(\n \":scope > .sidebar-content > .accordion\"\n );\n if (sideAccordion) {\n sideAccordion.classList.add(\"accordion-flush\");\n }\n\n if (this.layout.toggle) {\n this._initEventListeners();\n this._initSidebarCounters();\n this._initDesktop();\n }\n\n // Start watching the main content area for size changes to ensure Shiny\n // outputs resize appropriately during sidebar transitions.\n Sidebar.shinyResizeObserver.observe(this.layout.main);\n\n container.removeAttribute(\"data-bslib-sidebar-init\");\n const initScript = container.querySelector(\n \":scope > script[data-bslib-sidebar-init]\"\n );\n if (initScript) {\n container.removeChild(initScript);\n }\n }\n\n /**\n * Read the current state of the sidebar. Note that, when calling this method,\n * the sidebar may be transitioning into the state returned by this method.\n *\n * @description\n * The sidebar state works as follows, starting from the open state. When the\n * sidebar is closed:\n * 1. We add both the `COLLAPSE` and `TRANSITIONING` classes to the sidebar.\n * 2. The sidebar collapse begins to animate. On desktop devices, and where it\n * is supported, we transition the `grid-template-columns` property of the\n * sidebar layout. On mobile, the sidebar is hidden immediately. In both\n * cases, the collapse icon rotates and we use this rotation to determine\n * when the transition is complete.\n * 3. If another sidebar state toggle is requested while closing the sidebar,\n * we remove the `COLLAPSE` class and the animation immediately starts to\n * reverse.\n * 4. When the `transition` is complete, we remove the `TRANSITIONING` class.\n * @readonly\n * @type {boolean}\n */\n get isClosed(): boolean {\n return this.layout.container.classList.contains(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * Static classes related to the sidebar layout or state.\n * @public\n * @static\n * @readonly\n * @type {{ LAYOUT: string; COLLAPSE: string; TRANSITIONING: string; }}\n */\n public static readonly classes = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n LAYOUT: \"bslib-sidebar-layout\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n COLLAPSE: \"sidebar-collapsed\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n TRANSITIONING: \"transitioning\",\n };\n\n /**\n * If sidebars are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n /**\n * A map of initialized sidebars to their respective Sidebar instances.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Given a sidebar container, return the Sidebar instance associated with it.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Sidebar | undefined)}\n */\n public static getInstance(el: HTMLElement): Sidebar | undefined {\n return Sidebar.instanceMap.get(el);\n }\n\n /**\n * Initialize all collapsible sidebars on the page.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true] When `true`, we remove\n * non-existent elements from the ResizeObserver. This is required\n * periodically to prevent memory leaks. To avoid over-checking, we only flush\n * the ResizeObserver when initializing sidebars after page load.\n */\n public static initCollapsibleAll(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Sidebar.onReadyScheduled) {\n Sidebar.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Sidebar.initCollapsibleAll(false);\n });\n }\n return;\n }\n\n const initSelector = `.${Sidebar.classes.LAYOUT}[data-bslib-sidebar-init]`;\n if (!document.querySelector(initSelector)) {\n // no sidebars to initialize\n return;\n }\n\n if (flushResizeObserver) Sidebar.shinyResizeObserver.flush();\n\n const containers = document.querySelectorAll(initSelector);\n containers.forEach((container) => new Sidebar(container as HTMLElement));\n }\n\n /**\n * Initialize event listeners for the sidebar toggle button.\n * @private\n */\n private _initEventListeners(): void {\n const { toggle } = this.layout;\n\n toggle.addEventListener(\"click\", (ev) => {\n ev.preventDefault();\n this.toggle(\"toggle\");\n });\n\n // Remove the transitioning class when the transition ends. We watch the\n // collapse toggle icon because it's guaranteed to transition, whereas the\n // sidebar doesn't animate on mobile (or in browsers where animating\n // grid-template-columns is not supported).\n toggle\n .querySelector(\".collapse-icon\")\n ?.addEventListener(\"transitionend\", () => this._finalizeState());\n }\n\n /**\n * Initialize nested sidebar counters.\n *\n * @description\n * This function walks up the DOM tree, adding CSS variables to each direct\n * parent sidebar layout that count the layout's position in the stack of\n * nested layouts. We use these counters to keep the collapse toggles from\n * overlapping. Note that always-open sidebars that don't have collapse\n * toggles break the chain of nesting.\n * @private\n */\n private _initSidebarCounters(): void {\n const { container } = this.layout;\n\n const selectorChildLayouts =\n `.${Sidebar.classes.LAYOUT}` +\n \"> .main > \" +\n `.${Sidebar.classes.LAYOUT}:not([data-bslib-sidebar-open=\"always\"])`;\n\n const isInnermostLayout =\n container.querySelector(selectorChildLayouts) === null;\n\n if (!isInnermostLayout) {\n // There are sidebar layouts nested within this layout; defer to children\n return;\n }\n\n function nextSidebarParent(el: HTMLElement | null): HTMLElement | null {\n el = el ? el.parentElement : null;\n if (el && el.classList.contains(\"main\")) {\n // .bslib-sidebar-layout > .main > .bslib-sidebar-layout\n el = el.parentElement;\n }\n if (el && el.classList.contains(Sidebar.classes.LAYOUT)) {\n return el;\n }\n return null;\n }\n\n const layouts = [container];\n let parent = nextSidebarParent(container);\n\n while (parent) {\n // Add parent to front of layouts array, so we sort outer -> inner\n layouts.unshift(parent);\n parent = nextSidebarParent(parent);\n }\n\n const count = { left: 0, right: 0 };\n layouts.forEach(function (x: HTMLElement, i: number): void {\n x.style.setProperty(\"--bslib-sidebar-counter\", i.toString());\n const isRight = x.classList.contains(\"sidebar-right\");\n const thisCount = isRight ? count.right++ : count.left++;\n x.style.setProperty(\n \"--bslib-sidebar-overlap-counter\",\n thisCount.toString()\n );\n });\n }\n\n /**\n * Initialize the sidebar's initial state when `open = \"desktop\"`.\n * @private\n */\n private _initDesktop(): void {\n const { container } = this.layout;\n // If sidebar is marked open='desktop'...\n if (container.dataset.bslibSidebarOpen?.trim() !== \"desktop\") {\n return;\n }\n\n // then close sidebar on mobile\n const initCollapsed = window\n .getComputedStyle(container)\n .getPropertyValue(\"--bslib-sidebar-js-init-collapsed\");\n\n if (initCollapsed.trim() === \"true\") {\n this.toggle(\"close\");\n }\n }\n\n /**\n * Toggle the sidebar's open/closed state.\n * @public\n * @param {SidebarToggleMethod | undefined} method Whether to `\"open\"`,\n * `\"close\"` or `\"toggle\"` the sidebar. If `.toggle()` is called without an\n * argument, it will toggle the sidebar's state.\n */\n public toggle(method: SidebarToggleMethod | undefined): void {\n if (typeof method === \"undefined\") {\n method = \"toggle\";\n }\n\n const { container, sidebar } = this.layout;\n const isClosed = this.isClosed;\n\n if ([\"open\", \"close\", \"toggle\"].indexOf(method) === -1) {\n throw new Error(`Unknown method ${method}`);\n }\n\n if (method === \"toggle\") {\n method = isClosed ? \"open\" : \"close\";\n }\n\n if ((isClosed && method === \"close\") || (!isClosed && method === \"open\")) {\n // nothing to do, sidebar is already in the desired state\n return;\n }\n\n if (method === \"open\") {\n // unhide sidebar immediately when opening,\n // otherwise the sidebar is hidden on transitionend\n sidebar.hidden = false;\n }\n\n // Add a transitioning class just before adding COLLAPSE_CLASS since we want\n // some of the transitioning styles to apply before the collapse state\n container.classList.add(Sidebar.classes.TRANSITIONING);\n container.classList.toggle(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * When the sidebar open/close transition ends, finalize the sidebar's state.\n * @private\n */\n private _finalizeState(): void {\n const { container, sidebar, toggle } = this.layout;\n container.classList.remove(Sidebar.classes.TRANSITIONING);\n sidebar.hidden = this.isClosed;\n toggle.setAttribute(\"aria-expanded\", this.isClosed ? \"false\" : \"true\");\n\n // Send browser-native event with updated sidebar state\n const event = new CustomEvent(\"bslib.sidebar\", {\n bubbles: true,\n detail: { open: !this.isClosed },\n });\n sidebar.dispatchEvent(event);\n\n // Trigger Shiny input and output binding events\n $(sidebar).trigger(\"toggleCollapse.sidebarInputBinding\");\n $(sidebar).trigger(this.isClosed ? \"hidden\" : \"shown\");\n }\n}\n\n/**\n * A Shiny input binding for a sidebar.\n * @class SidebarInputBinding\n * @typedef {SidebarInputBinding}\n * @extends {InputBinding}\n */\nclass SidebarInputBinding extends InputBinding {\n find(scope: HTMLElement) {\n return $(scope).find(`.${Sidebar.classes.LAYOUT} > .bslib-sidebar-input`);\n }\n\n getValue(el: HTMLElement): boolean {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (!sb) return false;\n return !sb.isClosed;\n }\n\n setValue(el: HTMLElement, value: boolean): void {\n const method = value ? \"open\" : \"close\";\n this.receiveMessage(el, { method });\n }\n\n subscribe(el: HTMLElement, callback: (x: boolean) => void) {\n $(el).on(\n \"toggleCollapse.sidebarInputBinding\",\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n function (event) {\n callback(true);\n }\n );\n }\n\n unsubscribe(el: HTMLElement) {\n $(el).off(\".sidebarInputBinding\");\n }\n\n receiveMessage(el: HTMLElement, data: SidebarMessageData) {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (sb) sb.toggle(data.method);\n }\n}\n\nregisterBinding(SidebarInputBinding, \"sidebar\");\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Sidebar = Sidebar;\n"],
- "mappings": "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",
+ "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import { InputBinding, registerBinding } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n/**\n * Methods for programmatically toggling the state of the sidebar. These methods\n * describe the desired state of the sidebar: `\"close\"` and `\"open\"` transition\n * the sidebar to the desired state, unless the sidebar is already in that\n * state. `\"toggle\"` transitions the sidebar to the state opposite of its\n * current state.\n * @typedef {SidebarToggleMethod}\n */\ntype SidebarToggleMethod = \"close\" | \"open\" | \"toggle\";\n\n/**\n * Data received by the input binding's `receiveMessage` method.\n * @typedef {SidebarMessageData}\n */\ntype SidebarMessageData = {\n method: SidebarToggleMethod;\n};\n\n/**\n * The DOM elements that make up the sidebar. `main`, `sidebar`, and `toggle`\n * are all direct children of `container` (in that order).\n * @interface SidebarComponents\n * @typedef {SidebarComponents}\n */\ninterface SidebarComponents {\n /**\n * The `layout_sidebar()` parent container, with class\n * `Sidebar.classes.LAYOUT`.\n * @type {HTMLElement}\n */\n container: HTMLElement;\n /**\n * The main content area of the sidebar layout.\n * @type {HTMLElement}\n */\n main: HTMLElement;\n /**\n * The sidebar container of the sidebar layout.\n * @type {HTMLElement}\n */\n sidebar: HTMLElement;\n /**\n * The toggle button that is used to toggle the sidebar state.\n * @type {HTMLElement}\n */\n toggle: HTMLElement;\n}\n\n/**\n * The bslib sidebar component class. This class is only used for collapsible\n * sidebars.\n *\n * @class Sidebar\n * @typedef {Sidebar}\n */\nclass Sidebar {\n /**\n * The DOM elements that make up the sidebar, see `SidebarComponents`.\n * @private\n * @type {SidebarComponents}\n */\n private layout: SidebarComponents;\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in the main\n * content areas of the sidebar resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a collapsible bslib Sidebar.\n * @constructor\n * @param {HTMLElement} container\n */\n constructor(container: HTMLElement) {\n Sidebar.instanceMap.set(container, this);\n this.layout = {\n container,\n main: container.querySelector(\":scope > .main\") as HTMLElement,\n sidebar: container.querySelector(\":scope > .sidebar\") as HTMLElement,\n toggle: container.querySelector(\n \":scope > .collapse-toggle\"\n ) as HTMLElement,\n } as SidebarComponents;\n\n const sideAccordion = this.layout.sidebar.querySelector(\n \":scope > .sidebar-content > .accordion\"\n );\n if (sideAccordion) {\n // Add `.has-accordion` class to `.sidebar-content` container\n sideAccordion?.parentElement?.classList.add(\"has-accordion\");\n sideAccordion.classList.add(\"accordion-flush\");\n }\n\n if (this.layout.toggle) {\n this._initEventListeners();\n this._initSidebarCounters();\n this._initDesktop();\n }\n\n // Start watching the main content area for size changes to ensure Shiny\n // outputs resize appropriately during sidebar transitions.\n Sidebar.shinyResizeObserver.observe(this.layout.main);\n\n container.removeAttribute(\"data-bslib-sidebar-init\");\n const initScript = container.querySelector(\n \":scope > script[data-bslib-sidebar-init]\"\n );\n if (initScript) {\n container.removeChild(initScript);\n }\n }\n\n /**\n * Read the current state of the sidebar. Note that, when calling this method,\n * the sidebar may be transitioning into the state returned by this method.\n *\n * @description\n * The sidebar state works as follows, starting from the open state. When the\n * sidebar is closed:\n * 1. We add both the `COLLAPSE` and `TRANSITIONING` classes to the sidebar.\n * 2. The sidebar collapse begins to animate. On desktop devices, and where it\n * is supported, we transition the `grid-template-columns` property of the\n * sidebar layout. On mobile, the sidebar is hidden immediately. In both\n * cases, the collapse icon rotates and we use this rotation to determine\n * when the transition is complete.\n * 3. If another sidebar state toggle is requested while closing the sidebar,\n * we remove the `COLLAPSE` class and the animation immediately starts to\n * reverse.\n * 4. When the `transition` is complete, we remove the `TRANSITIONING` class.\n * @readonly\n * @type {boolean}\n */\n get isClosed(): boolean {\n return this.layout.container.classList.contains(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * Static classes related to the sidebar layout or state.\n * @public\n * @static\n * @readonly\n * @type {{ LAYOUT: string; COLLAPSE: string; TRANSITIONING: string; }}\n */\n public static readonly classes = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n LAYOUT: \"bslib-sidebar-layout\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n COLLAPSE: \"sidebar-collapsed\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n TRANSITIONING: \"transitioning\",\n };\n\n /**\n * If sidebars are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n /**\n * A map of initialized sidebars to their respective Sidebar instances.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Given a sidebar container, return the Sidebar instance associated with it.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Sidebar | undefined)}\n */\n public static getInstance(el: HTMLElement): Sidebar | undefined {\n return Sidebar.instanceMap.get(el);\n }\n\n /**\n * Initialize all collapsible sidebars on the page.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true] When `true`, we remove\n * non-existent elements from the ResizeObserver. This is required\n * periodically to prevent memory leaks. To avoid over-checking, we only flush\n * the ResizeObserver when initializing sidebars after page load.\n */\n public static initCollapsibleAll(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Sidebar.onReadyScheduled) {\n Sidebar.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Sidebar.initCollapsibleAll(false);\n });\n }\n return;\n }\n\n const initSelector = `.${Sidebar.classes.LAYOUT}[data-bslib-sidebar-init]`;\n if (!document.querySelector(initSelector)) {\n // no sidebars to initialize\n return;\n }\n\n if (flushResizeObserver) Sidebar.shinyResizeObserver.flush();\n\n const containers = document.querySelectorAll(initSelector);\n containers.forEach((container) => new Sidebar(container as HTMLElement));\n }\n\n /**\n * Initialize event listeners for the sidebar toggle button.\n * @private\n */\n private _initEventListeners(): void {\n const { toggle } = this.layout;\n\n toggle.addEventListener(\"click\", (ev) => {\n ev.preventDefault();\n this.toggle(\"toggle\");\n });\n\n // Remove the transitioning class when the transition ends. We watch the\n // collapse toggle icon because it's guaranteed to transition, whereas the\n // sidebar doesn't animate on mobile (or in browsers where animating\n // grid-template-columns is not supported).\n toggle\n .querySelector(\".collapse-icon\")\n ?.addEventListener(\"transitionend\", () => this._finalizeState());\n }\n\n /**\n * Initialize nested sidebar counters.\n *\n * @description\n * This function walks up the DOM tree, adding CSS variables to each direct\n * parent sidebar layout that count the layout's position in the stack of\n * nested layouts. We use these counters to keep the collapse toggles from\n * overlapping. Note that always-open sidebars that don't have collapse\n * toggles break the chain of nesting.\n * @private\n */\n private _initSidebarCounters(): void {\n const { container } = this.layout;\n\n const selectorChildLayouts =\n `.${Sidebar.classes.LAYOUT}` +\n \"> .main > \" +\n `.${Sidebar.classes.LAYOUT}:not([data-bslib-sidebar-open=\"always\"])`;\n\n const isInnermostLayout =\n container.querySelector(selectorChildLayouts) === null;\n\n if (!isInnermostLayout) {\n // There are sidebar layouts nested within this layout; defer to children\n return;\n }\n\n function nextSidebarParent(el: HTMLElement | null): HTMLElement | null {\n el = el ? el.parentElement : null;\n if (el && el.classList.contains(\"main\")) {\n // .bslib-sidebar-layout > .main > .bslib-sidebar-layout\n el = el.parentElement;\n }\n if (el && el.classList.contains(Sidebar.classes.LAYOUT)) {\n return el;\n }\n return null;\n }\n\n const layouts = [container];\n let parent = nextSidebarParent(container);\n\n while (parent) {\n // Add parent to front of layouts array, so we sort outer -> inner\n layouts.unshift(parent);\n parent = nextSidebarParent(parent);\n }\n\n const count = { left: 0, right: 0 };\n layouts.forEach(function (x: HTMLElement, i: number): void {\n x.style.setProperty(\"--bslib-sidebar-counter\", i.toString());\n const isRight = x.classList.contains(\"sidebar-right\");\n const thisCount = isRight ? count.right++ : count.left++;\n x.style.setProperty(\n \"--bslib-sidebar-overlap-counter\",\n thisCount.toString()\n );\n });\n }\n\n /**\n * Initialize the sidebar's initial state when `open = \"desktop\"`.\n * @private\n */\n private _initDesktop(): void {\n const { container } = this.layout;\n // If sidebar is marked open='desktop'...\n if (container.dataset.bslibSidebarOpen?.trim() !== \"desktop\") {\n return;\n }\n\n // then close sidebar on mobile\n const initCollapsed = window\n .getComputedStyle(container)\n .getPropertyValue(\"--bslib-sidebar-js-init-collapsed\");\n\n if (initCollapsed.trim() === \"true\") {\n this.toggle(\"close\");\n }\n }\n\n /**\n * Toggle the sidebar's open/closed state.\n * @public\n * @param {SidebarToggleMethod | undefined} method Whether to `\"open\"`,\n * `\"close\"` or `\"toggle\"` the sidebar. If `.toggle()` is called without an\n * argument, it will toggle the sidebar's state.\n */\n public toggle(method: SidebarToggleMethod | undefined): void {\n if (typeof method === \"undefined\") {\n method = \"toggle\";\n }\n\n const { container, sidebar } = this.layout;\n const isClosed = this.isClosed;\n\n if ([\"open\", \"close\", \"toggle\"].indexOf(method) === -1) {\n throw new Error(`Unknown method ${method}`);\n }\n\n if (method === \"toggle\") {\n method = isClosed ? \"open\" : \"close\";\n }\n\n if ((isClosed && method === \"close\") || (!isClosed && method === \"open\")) {\n // nothing to do, sidebar is already in the desired state\n return;\n }\n\n if (method === \"open\") {\n // unhide sidebar immediately when opening,\n // otherwise the sidebar is hidden on transitionend\n sidebar.hidden = false;\n }\n\n // Add a transitioning class just before adding COLLAPSE_CLASS since we want\n // some of the transitioning styles to apply before the collapse state\n container.classList.add(Sidebar.classes.TRANSITIONING);\n container.classList.toggle(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * When the sidebar open/close transition ends, finalize the sidebar's state.\n * @private\n */\n private _finalizeState(): void {\n const { container, sidebar, toggle } = this.layout;\n container.classList.remove(Sidebar.classes.TRANSITIONING);\n sidebar.hidden = this.isClosed;\n toggle.setAttribute(\"aria-expanded\", this.isClosed ? \"false\" : \"true\");\n\n // Send browser-native event with updated sidebar state\n const event = new CustomEvent(\"bslib.sidebar\", {\n bubbles: true,\n detail: { open: !this.isClosed },\n });\n sidebar.dispatchEvent(event);\n\n // Trigger Shiny input and output binding events\n $(sidebar).trigger(\"toggleCollapse.sidebarInputBinding\");\n $(sidebar).trigger(this.isClosed ? \"hidden\" : \"shown\");\n }\n}\n\n/**\n * A Shiny input binding for a sidebar.\n * @class SidebarInputBinding\n * @typedef {SidebarInputBinding}\n * @extends {InputBinding}\n */\nclass SidebarInputBinding extends InputBinding {\n find(scope: HTMLElement) {\n return $(scope).find(`.${Sidebar.classes.LAYOUT} > .bslib-sidebar-input`);\n }\n\n getValue(el: HTMLElement): boolean {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (!sb) return false;\n return !sb.isClosed;\n }\n\n setValue(el: HTMLElement, value: boolean): void {\n const method = value ? \"open\" : \"close\";\n this.receiveMessage(el, { method });\n }\n\n subscribe(el: HTMLElement, callback: (x: boolean) => void) {\n $(el).on(\n \"toggleCollapse.sidebarInputBinding\",\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n function (event) {\n callback(true);\n }\n );\n }\n\n unsubscribe(el: HTMLElement) {\n $(el).off(\".sidebarInputBinding\");\n }\n\n receiveMessage(el: HTMLElement, data: SidebarMessageData) {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (sb) sb.toggle(data.method);\n }\n}\n\nregisterBinding(SidebarInputBinding, \"sidebar\");\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Sidebar = Sidebar;\n"],
+ "mappings": "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",
"names": []
}
diff --git a/inst/components/dist/sidebar/sidebar.min.js b/inst/components/dist/sidebar/sidebar.min.js
index 4c2e1d472..41cccfe23 100644
--- a/inst/components/dist/sidebar/sidebar.min.js
+++ b/inst/components/dist/sidebar/sidebar.min.js
@@ -1,3 +1,3 @@
/*! bslib 0.5.1.9000 | (c) 2012-2023 RStudio, PBC. | License: MIT + file LICENSE */
-"use strict";(()=>{var g=window.Shiny?Shiny.InputBinding:class{};function f(b,e){window.Shiny&&Shiny.inputBindings.register(new b,"bslib."+e)}var u=class{constructor(){this.resizeObserverEntries=[],this.resizeObserver=new ResizeObserver(e=>{let t=new Event("resize");if(window.dispatchEvent(t),!window.Shiny)return;let s=[];for(let r of e)r.target instanceof HTMLElement&&r.target.querySelector(".shiny-bound-output")&&r.target.querySelectorAll(".shiny-bound-output").forEach(o=>{if(s.includes(o))return;let{binding:l,onResize:d}=$(o).data("shinyOutputBinding");if(!l||!l.resize)return;let i=o.shinyResizeObserver;if(i&&i!==this||(i||(o.shinyResizeObserver=this),d(o),s.push(o),!o.classList.contains("shiny-plot-output")))return;let c=o.querySelector('img:not([width="100%"])');c&&c.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 n=class{constructor(e){n.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&&t.classList.add("accordion-flush"),this.layout.toggle&&(this._initEventListeners(),this._initSidebarCounters(),this._initDesktop()),n.shinyResizeObserver.observe(this.layout.main),e.removeAttribute("data-bslib-sidebar-init");let s=e.querySelector(":scope > script[data-bslib-sidebar-init]");s&&e.removeChild(s)}get isClosed(){return this.layout.container.classList.contains(n.classes.COLLAPSE)}static getInstance(e){return n.instanceMap.get(e)}static initCollapsibleAll(e=!0){if(document.readyState==="loading"){n.onReadyScheduled||(n.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{n.initCollapsibleAll(!1)}));return}let t=`.${n.classes.LAYOUT}[data-bslib-sidebar-init]`;if(!document.querySelector(t))return;e&&n.shinyResizeObserver.flush(),document.querySelectorAll(t).forEach(r=>new n(r))}_initEventListeners(){var t;let{toggle:e}=this.layout;e.addEventListener("click",s=>{s.preventDefault(),this.toggle("toggle")}),(t=e.querySelector(".collapse-icon"))==null||t.addEventListener("transitionend",()=>this._finalizeState())}_initSidebarCounters(){let{container:e}=this.layout,t=`.${n.classes.LAYOUT}> .main > .${n.classes.LAYOUT}:not([data-bslib-sidebar-open="always"])`;if(!(e.querySelector(t)===null))return;function r(i){return i=i?i.parentElement:null,i&&i.classList.contains("main")&&(i=i.parentElement),i&&i.classList.contains(n.classes.LAYOUT)?i:null}let o=[e],l=r(e);for(;l;)o.unshift(l),l=r(l);let d={left:0,right:0};o.forEach(function(i,c){i.style.setProperty("--bslib-sidebar-counter",c.toString());let y=i.classList.contains("sidebar-right")?d.right++:d.left++;i.style.setProperty("--bslib-sidebar-overlap-counter",y.toString())})}_initDesktop(){var s;let{container:e}=this.layout;if(((s=e.dataset.bslibSidebarOpen)==null?void 0:s.trim())!=="desktop")return;window.getComputedStyle(e).getPropertyValue("--bslib-sidebar-js-init-collapsed").trim()==="true"&&this.toggle("close")}toggle(e){typeof e=="undefined"&&(e="toggle");let{container:t,sidebar:s}=this.layout,r=this.isClosed;if(["open","close","toggle"].indexOf(e)===-1)throw new Error(`Unknown method ${e}`);e==="toggle"&&(e=r?"open":"close"),!(r&&e==="close"||!r&&e==="open")&&(e==="open"&&(s.hidden=!1),t.classList.add(n.classes.TRANSITIONING),t.classList.toggle(n.classes.COLLAPSE))}_finalizeState(){let{container:e,sidebar:t,toggle:s}=this.layout;e.classList.remove(n.classes.TRANSITIONING),t.hidden=this.isClosed,s.setAttribute("aria-expanded",this.isClosed?"false":"true");let r=new CustomEvent("bslib.sidebar",{bubbles:!0,detail:{open:!this.isClosed}});t.dispatchEvent(r),$(t).trigger("toggleCollapse.sidebarInputBinding"),$(t).trigger(this.isClosed?"hidden":"shown")}},a=n;a.shinyResizeObserver=new u,a.classes={LAYOUT:"bslib-sidebar-layout",COLLAPSE:"sidebar-collapsed",TRANSITIONING:"transitioning"},a.onReadyScheduled=!1,a.instanceMap=new WeakMap;var p=class extends g{find(e){return $(e).find(`.${a.classes.LAYOUT} > .bslib-sidebar-input`)}getValue(e){let t=a.getInstance(e.parentElement);return t?!t.isClosed:!1}setValue(e,t){let s=t?"open":"close";this.receiveMessage(e,{method:s})}subscribe(e,t){$(e).on("toggleCollapse.sidebarInputBinding",function(s){t(!0)})}unsubscribe(e){$(e).off(".sidebarInputBinding")}receiveMessage(e,t){let s=a.getInstance(e.parentElement);s&&s.toggle(t.method)}};f(p,"sidebar");window.bslib=window.bslib||{};window.bslib.Sidebar=a;})();
+"use strict";(()=>{var g=window.Shiny?Shiny.InputBinding:class{};function f(b,e){window.Shiny&&Shiny.inputBindings.register(new b,"bslib."+e)}var u=class{constructor(){this.resizeObserverEntries=[],this.resizeObserver=new ResizeObserver(e=>{let t=new Event("resize");if(window.dispatchEvent(t),!window.Shiny)return;let s=[];for(let r of e)r.target instanceof HTMLElement&&r.target.querySelector(".shiny-bound-output")&&r.target.querySelectorAll(".shiny-bound-output").forEach(o=>{if(s.includes(o))return;let{binding:l,onResize:d}=$(o).data("shinyOutputBinding");if(!l||!l.resize)return;let i=o.shinyResizeObserver;if(i&&i!==this||(i||(o.shinyResizeObserver=this),d(o),s.push(o),!o.classList.contains("shiny-plot-output")))return;let c=o.querySelector('img:not([width="100%"])');c&&c.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 n=class{constructor(e){var r;n.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&&((r=t==null?void 0:t.parentElement)==null||r.classList.add("has-accordion"),t.classList.add("accordion-flush")),this.layout.toggle&&(this._initEventListeners(),this._initSidebarCounters(),this._initDesktop()),n.shinyResizeObserver.observe(this.layout.main),e.removeAttribute("data-bslib-sidebar-init");let s=e.querySelector(":scope > script[data-bslib-sidebar-init]");s&&e.removeChild(s)}get isClosed(){return this.layout.container.classList.contains(n.classes.COLLAPSE)}static getInstance(e){return n.instanceMap.get(e)}static initCollapsibleAll(e=!0){if(document.readyState==="loading"){n.onReadyScheduled||(n.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{n.initCollapsibleAll(!1)}));return}let t=`.${n.classes.LAYOUT}[data-bslib-sidebar-init]`;if(!document.querySelector(t))return;e&&n.shinyResizeObserver.flush(),document.querySelectorAll(t).forEach(r=>new n(r))}_initEventListeners(){var t;let{toggle:e}=this.layout;e.addEventListener("click",s=>{s.preventDefault(),this.toggle("toggle")}),(t=e.querySelector(".collapse-icon"))==null||t.addEventListener("transitionend",()=>this._finalizeState())}_initSidebarCounters(){let{container:e}=this.layout,t=`.${n.classes.LAYOUT}> .main > .${n.classes.LAYOUT}:not([data-bslib-sidebar-open="always"])`;if(!(e.querySelector(t)===null))return;function r(i){return i=i?i.parentElement:null,i&&i.classList.contains("main")&&(i=i.parentElement),i&&i.classList.contains(n.classes.LAYOUT)?i:null}let o=[e],l=r(e);for(;l;)o.unshift(l),l=r(l);let d={left:0,right:0};o.forEach(function(i,c){i.style.setProperty("--bslib-sidebar-counter",c.toString());let h=i.classList.contains("sidebar-right")?d.right++:d.left++;i.style.setProperty("--bslib-sidebar-overlap-counter",h.toString())})}_initDesktop(){var s;let{container:e}=this.layout;if(((s=e.dataset.bslibSidebarOpen)==null?void 0:s.trim())!=="desktop")return;window.getComputedStyle(e).getPropertyValue("--bslib-sidebar-js-init-collapsed").trim()==="true"&&this.toggle("close")}toggle(e){typeof e=="undefined"&&(e="toggle");let{container:t,sidebar:s}=this.layout,r=this.isClosed;if(["open","close","toggle"].indexOf(e)===-1)throw new Error(`Unknown method ${e}`);e==="toggle"&&(e=r?"open":"close"),!(r&&e==="close"||!r&&e==="open")&&(e==="open"&&(s.hidden=!1),t.classList.add(n.classes.TRANSITIONING),t.classList.toggle(n.classes.COLLAPSE))}_finalizeState(){let{container:e,sidebar:t,toggle:s}=this.layout;e.classList.remove(n.classes.TRANSITIONING),t.hidden=this.isClosed,s.setAttribute("aria-expanded",this.isClosed?"false":"true");let r=new CustomEvent("bslib.sidebar",{bubbles:!0,detail:{open:!this.isClosed}});t.dispatchEvent(r),$(t).trigger("toggleCollapse.sidebarInputBinding"),$(t).trigger(this.isClosed?"hidden":"shown")}},a=n;a.shinyResizeObserver=new u,a.classes={LAYOUT:"bslib-sidebar-layout",COLLAPSE:"sidebar-collapsed",TRANSITIONING:"transitioning"},a.onReadyScheduled=!1,a.instanceMap=new WeakMap;var p=class extends g{find(e){return $(e).find(`.${a.classes.LAYOUT} > .bslib-sidebar-input`)}getValue(e){let t=a.getInstance(e.parentElement);return t?!t.isClosed:!1}setValue(e,t){let s=t?"open":"close";this.receiveMessage(e,{method:s})}subscribe(e,t){$(e).on("toggleCollapse.sidebarInputBinding",function(s){t(!0)})}unsubscribe(e){$(e).off(".sidebarInputBinding")}receiveMessage(e,t){let s=a.getInstance(e.parentElement);s&&s.toggle(t.method)}};f(p,"sidebar");window.bslib=window.bslib||{};window.bslib.Sidebar=a;})();
//# sourceMappingURL=sidebar.min.js.map
diff --git a/inst/components/dist/sidebar/sidebar.min.js.map b/inst/components/dist/sidebar/sidebar.min.js.map
index fc2cc02ea..c6eeefff3 100644
--- a/inst/components/dist/sidebar/sidebar.min.js.map
+++ b/inst/components/dist/sidebar/sidebar.min.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../../../srcts/src/components/_utils.ts", "../../../../srcts/src/components/_shinyResizeObserver.ts", "../../../../srcts/src/components/sidebar.ts"],
- "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import { InputBinding, registerBinding } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n/**\n * Methods for programmatically toggling the state of the sidebar. These methods\n * describe the desired state of the sidebar: `\"close\"` and `\"open\"` transition\n * the sidebar to the desired state, unless the sidebar is already in that\n * state. `\"toggle\"` transitions the sidebar to the state opposite of its\n * current state.\n * @typedef {SidebarToggleMethod}\n */\ntype SidebarToggleMethod = \"close\" | \"open\" | \"toggle\";\n\n/**\n * Data received by the input binding's `receiveMessage` method.\n * @typedef {SidebarMessageData}\n */\ntype SidebarMessageData = {\n method: SidebarToggleMethod;\n};\n\n/**\n * The DOM elements that make up the sidebar. `main`, `sidebar`, and `toggle`\n * are all direct children of `container` (in that order).\n * @interface SidebarComponents\n * @typedef {SidebarComponents}\n */\ninterface SidebarComponents {\n /**\n * The `layout_sidebar()` parent container, with class\n * `Sidebar.classes.LAYOUT`.\n * @type {HTMLElement}\n */\n container: HTMLElement;\n /**\n * The main content area of the sidebar layout.\n * @type {HTMLElement}\n */\n main: HTMLElement;\n /**\n * The sidebar container of the sidebar layout.\n * @type {HTMLElement}\n */\n sidebar: HTMLElement;\n /**\n * The toggle button that is used to toggle the sidebar state.\n * @type {HTMLElement}\n */\n toggle: HTMLElement;\n}\n\n/**\n * The bslib sidebar component class. This class is only used for collapsible\n * sidebars.\n *\n * @class Sidebar\n * @typedef {Sidebar}\n */\nclass Sidebar {\n /**\n * The DOM elements that make up the sidebar, see `SidebarComponents`.\n * @private\n * @type {SidebarComponents}\n */\n private layout: SidebarComponents;\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in the main\n * content areas of the sidebar resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a collapsible bslib Sidebar.\n * @constructor\n * @param {HTMLElement} container\n */\n constructor(container: HTMLElement) {\n Sidebar.instanceMap.set(container, this);\n this.layout = {\n container,\n main: container.querySelector(\":scope > .main\") as HTMLElement,\n sidebar: container.querySelector(\":scope > .sidebar\") as HTMLElement,\n toggle: container.querySelector(\n \":scope > .collapse-toggle\"\n ) as HTMLElement,\n } as SidebarComponents;\n\n const sideAccordion = this.layout.sidebar.querySelector(\n \":scope > .sidebar-content > .accordion\"\n );\n if (sideAccordion) {\n sideAccordion.classList.add(\"accordion-flush\");\n }\n\n if (this.layout.toggle) {\n this._initEventListeners();\n this._initSidebarCounters();\n this._initDesktop();\n }\n\n // Start watching the main content area for size changes to ensure Shiny\n // outputs resize appropriately during sidebar transitions.\n Sidebar.shinyResizeObserver.observe(this.layout.main);\n\n container.removeAttribute(\"data-bslib-sidebar-init\");\n const initScript = container.querySelector(\n \":scope > script[data-bslib-sidebar-init]\"\n );\n if (initScript) {\n container.removeChild(initScript);\n }\n }\n\n /**\n * Read the current state of the sidebar. Note that, when calling this method,\n * the sidebar may be transitioning into the state returned by this method.\n *\n * @description\n * The sidebar state works as follows, starting from the open state. When the\n * sidebar is closed:\n * 1. We add both the `COLLAPSE` and `TRANSITIONING` classes to the sidebar.\n * 2. The sidebar collapse begins to animate. On desktop devices, and where it\n * is supported, we transition the `grid-template-columns` property of the\n * sidebar layout. On mobile, the sidebar is hidden immediately. In both\n * cases, the collapse icon rotates and we use this rotation to determine\n * when the transition is complete.\n * 3. If another sidebar state toggle is requested while closing the sidebar,\n * we remove the `COLLAPSE` class and the animation immediately starts to\n * reverse.\n * 4. When the `transition` is complete, we remove the `TRANSITIONING` class.\n * @readonly\n * @type {boolean}\n */\n get isClosed(): boolean {\n return this.layout.container.classList.contains(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * Static classes related to the sidebar layout or state.\n * @public\n * @static\n * @readonly\n * @type {{ LAYOUT: string; COLLAPSE: string; TRANSITIONING: string; }}\n */\n public static readonly classes = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n LAYOUT: \"bslib-sidebar-layout\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n COLLAPSE: \"sidebar-collapsed\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n TRANSITIONING: \"transitioning\",\n };\n\n /**\n * If sidebars are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n /**\n * A map of initialized sidebars to their respective Sidebar instances.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Given a sidebar container, return the Sidebar instance associated with it.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Sidebar | undefined)}\n */\n public static getInstance(el: HTMLElement): Sidebar | undefined {\n return Sidebar.instanceMap.get(el);\n }\n\n /**\n * Initialize all collapsible sidebars on the page.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true] When `true`, we remove\n * non-existent elements from the ResizeObserver. This is required\n * periodically to prevent memory leaks. To avoid over-checking, we only flush\n * the ResizeObserver when initializing sidebars after page load.\n */\n public static initCollapsibleAll(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Sidebar.onReadyScheduled) {\n Sidebar.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Sidebar.initCollapsibleAll(false);\n });\n }\n return;\n }\n\n const initSelector = `.${Sidebar.classes.LAYOUT}[data-bslib-sidebar-init]`;\n if (!document.querySelector(initSelector)) {\n // no sidebars to initialize\n return;\n }\n\n if (flushResizeObserver) Sidebar.shinyResizeObserver.flush();\n\n const containers = document.querySelectorAll(initSelector);\n containers.forEach((container) => new Sidebar(container as HTMLElement));\n }\n\n /**\n * Initialize event listeners for the sidebar toggle button.\n * @private\n */\n private _initEventListeners(): void {\n const { toggle } = this.layout;\n\n toggle.addEventListener(\"click\", (ev) => {\n ev.preventDefault();\n this.toggle(\"toggle\");\n });\n\n // Remove the transitioning class when the transition ends. We watch the\n // collapse toggle icon because it's guaranteed to transition, whereas the\n // sidebar doesn't animate on mobile (or in browsers where animating\n // grid-template-columns is not supported).\n toggle\n .querySelector(\".collapse-icon\")\n ?.addEventListener(\"transitionend\", () => this._finalizeState());\n }\n\n /**\n * Initialize nested sidebar counters.\n *\n * @description\n * This function walks up the DOM tree, adding CSS variables to each direct\n * parent sidebar layout that count the layout's position in the stack of\n * nested layouts. We use these counters to keep the collapse toggles from\n * overlapping. Note that always-open sidebars that don't have collapse\n * toggles break the chain of nesting.\n * @private\n */\n private _initSidebarCounters(): void {\n const { container } = this.layout;\n\n const selectorChildLayouts =\n `.${Sidebar.classes.LAYOUT}` +\n \"> .main > \" +\n `.${Sidebar.classes.LAYOUT}:not([data-bslib-sidebar-open=\"always\"])`;\n\n const isInnermostLayout =\n container.querySelector(selectorChildLayouts) === null;\n\n if (!isInnermostLayout) {\n // There are sidebar layouts nested within this layout; defer to children\n return;\n }\n\n function nextSidebarParent(el: HTMLElement | null): HTMLElement | null {\n el = el ? el.parentElement : null;\n if (el && el.classList.contains(\"main\")) {\n // .bslib-sidebar-layout > .main > .bslib-sidebar-layout\n el = el.parentElement;\n }\n if (el && el.classList.contains(Sidebar.classes.LAYOUT)) {\n return el;\n }\n return null;\n }\n\n const layouts = [container];\n let parent = nextSidebarParent(container);\n\n while (parent) {\n // Add parent to front of layouts array, so we sort outer -> inner\n layouts.unshift(parent);\n parent = nextSidebarParent(parent);\n }\n\n const count = { left: 0, right: 0 };\n layouts.forEach(function (x: HTMLElement, i: number): void {\n x.style.setProperty(\"--bslib-sidebar-counter\", i.toString());\n const isRight = x.classList.contains(\"sidebar-right\");\n const thisCount = isRight ? count.right++ : count.left++;\n x.style.setProperty(\n \"--bslib-sidebar-overlap-counter\",\n thisCount.toString()\n );\n });\n }\n\n /**\n * Initialize the sidebar's initial state when `open = \"desktop\"`.\n * @private\n */\n private _initDesktop(): void {\n const { container } = this.layout;\n // If sidebar is marked open='desktop'...\n if (container.dataset.bslibSidebarOpen?.trim() !== \"desktop\") {\n return;\n }\n\n // then close sidebar on mobile\n const initCollapsed = window\n .getComputedStyle(container)\n .getPropertyValue(\"--bslib-sidebar-js-init-collapsed\");\n\n if (initCollapsed.trim() === \"true\") {\n this.toggle(\"close\");\n }\n }\n\n /**\n * Toggle the sidebar's open/closed state.\n * @public\n * @param {SidebarToggleMethod | undefined} method Whether to `\"open\"`,\n * `\"close\"` or `\"toggle\"` the sidebar. If `.toggle()` is called without an\n * argument, it will toggle the sidebar's state.\n */\n public toggle(method: SidebarToggleMethod | undefined): void {\n if (typeof method === \"undefined\") {\n method = \"toggle\";\n }\n\n const { container, sidebar } = this.layout;\n const isClosed = this.isClosed;\n\n if ([\"open\", \"close\", \"toggle\"].indexOf(method) === -1) {\n throw new Error(`Unknown method ${method}`);\n }\n\n if (method === \"toggle\") {\n method = isClosed ? \"open\" : \"close\";\n }\n\n if ((isClosed && method === \"close\") || (!isClosed && method === \"open\")) {\n // nothing to do, sidebar is already in the desired state\n return;\n }\n\n if (method === \"open\") {\n // unhide sidebar immediately when opening,\n // otherwise the sidebar is hidden on transitionend\n sidebar.hidden = false;\n }\n\n // Add a transitioning class just before adding COLLAPSE_CLASS since we want\n // some of the transitioning styles to apply before the collapse state\n container.classList.add(Sidebar.classes.TRANSITIONING);\n container.classList.toggle(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * When the sidebar open/close transition ends, finalize the sidebar's state.\n * @private\n */\n private _finalizeState(): void {\n const { container, sidebar, toggle } = this.layout;\n container.classList.remove(Sidebar.classes.TRANSITIONING);\n sidebar.hidden = this.isClosed;\n toggle.setAttribute(\"aria-expanded\", this.isClosed ? \"false\" : \"true\");\n\n // Send browser-native event with updated sidebar state\n const event = new CustomEvent(\"bslib.sidebar\", {\n bubbles: true,\n detail: { open: !this.isClosed },\n });\n sidebar.dispatchEvent(event);\n\n // Trigger Shiny input and output binding events\n $(sidebar).trigger(\"toggleCollapse.sidebarInputBinding\");\n $(sidebar).trigger(this.isClosed ? \"hidden\" : \"shown\");\n }\n}\n\n/**\n * A Shiny input binding for a sidebar.\n * @class SidebarInputBinding\n * @typedef {SidebarInputBinding}\n * @extends {InputBinding}\n */\nclass SidebarInputBinding extends InputBinding {\n find(scope: HTMLElement) {\n return $(scope).find(`.${Sidebar.classes.LAYOUT} > .bslib-sidebar-input`);\n }\n\n getValue(el: HTMLElement): boolean {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (!sb) return false;\n return !sb.isClosed;\n }\n\n setValue(el: HTMLElement, value: boolean): void {\n const method = value ? \"open\" : \"close\";\n this.receiveMessage(el, { method });\n }\n\n subscribe(el: HTMLElement, callback: (x: boolean) => void) {\n $(el).on(\n \"toggleCollapse.sidebarInputBinding\",\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n function (event) {\n callback(true);\n }\n );\n }\n\n unsubscribe(el: HTMLElement) {\n $(el).off(\".sidebarInputBinding\");\n }\n\n receiveMessage(el: HTMLElement, data: SidebarMessageData) {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (sb) sb.toggle(data.method);\n }\n}\n\nregisterBinding(SidebarInputBinding, \"sidebar\");\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Sidebar = Sidebar;\n"],
- "mappings": "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",
- "names": ["InputBinding", "registerBinding", "inputBindingClass", "name", "ShinyResizeObserver", "entries", "resizeEvent", "resized", "entry", "el", "binding", "onResize", "owner", "img", "idxEl", "_Sidebar", "container", "sideAccordion", "initScript", "el", "flushResizeObserver", "initSelector", "_a", "toggle", "ev", "selectorChildLayouts", "nextSidebarParent", "layouts", "parent", "count", "x", "i", "thisCount", "method", "sidebar", "isClosed", "event", "Sidebar", "ShinyResizeObserver", "SidebarInputBinding", "InputBinding", "scope", "sb", "value", "callback", "data", "registerBinding"]
+ "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import { InputBinding, registerBinding } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n/**\n * Methods for programmatically toggling the state of the sidebar. These methods\n * describe the desired state of the sidebar: `\"close\"` and `\"open\"` transition\n * the sidebar to the desired state, unless the sidebar is already in that\n * state. `\"toggle\"` transitions the sidebar to the state opposite of its\n * current state.\n * @typedef {SidebarToggleMethod}\n */\ntype SidebarToggleMethod = \"close\" | \"open\" | \"toggle\";\n\n/**\n * Data received by the input binding's `receiveMessage` method.\n * @typedef {SidebarMessageData}\n */\ntype SidebarMessageData = {\n method: SidebarToggleMethod;\n};\n\n/**\n * The DOM elements that make up the sidebar. `main`, `sidebar`, and `toggle`\n * are all direct children of `container` (in that order).\n * @interface SidebarComponents\n * @typedef {SidebarComponents}\n */\ninterface SidebarComponents {\n /**\n * The `layout_sidebar()` parent container, with class\n * `Sidebar.classes.LAYOUT`.\n * @type {HTMLElement}\n */\n container: HTMLElement;\n /**\n * The main content area of the sidebar layout.\n * @type {HTMLElement}\n */\n main: HTMLElement;\n /**\n * The sidebar container of the sidebar layout.\n * @type {HTMLElement}\n */\n sidebar: HTMLElement;\n /**\n * The toggle button that is used to toggle the sidebar state.\n * @type {HTMLElement}\n */\n toggle: HTMLElement;\n}\n\n/**\n * The bslib sidebar component class. This class is only used for collapsible\n * sidebars.\n *\n * @class Sidebar\n * @typedef {Sidebar}\n */\nclass Sidebar {\n /**\n * The DOM elements that make up the sidebar, see `SidebarComponents`.\n * @private\n * @type {SidebarComponents}\n */\n private layout: SidebarComponents;\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in the main\n * content areas of the sidebar resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a collapsible bslib Sidebar.\n * @constructor\n * @param {HTMLElement} container\n */\n constructor(container: HTMLElement) {\n Sidebar.instanceMap.set(container, this);\n this.layout = {\n container,\n main: container.querySelector(\":scope > .main\") as HTMLElement,\n sidebar: container.querySelector(\":scope > .sidebar\") as HTMLElement,\n toggle: container.querySelector(\n \":scope > .collapse-toggle\"\n ) as HTMLElement,\n } as SidebarComponents;\n\n const sideAccordion = this.layout.sidebar.querySelector(\n \":scope > .sidebar-content > .accordion\"\n );\n if (sideAccordion) {\n // Add `.has-accordion` class to `.sidebar-content` container\n sideAccordion?.parentElement?.classList.add(\"has-accordion\");\n sideAccordion.classList.add(\"accordion-flush\");\n }\n\n if (this.layout.toggle) {\n this._initEventListeners();\n this._initSidebarCounters();\n this._initDesktop();\n }\n\n // Start watching the main content area for size changes to ensure Shiny\n // outputs resize appropriately during sidebar transitions.\n Sidebar.shinyResizeObserver.observe(this.layout.main);\n\n container.removeAttribute(\"data-bslib-sidebar-init\");\n const initScript = container.querySelector(\n \":scope > script[data-bslib-sidebar-init]\"\n );\n if (initScript) {\n container.removeChild(initScript);\n }\n }\n\n /**\n * Read the current state of the sidebar. Note that, when calling this method,\n * the sidebar may be transitioning into the state returned by this method.\n *\n * @description\n * The sidebar state works as follows, starting from the open state. When the\n * sidebar is closed:\n * 1. We add both the `COLLAPSE` and `TRANSITIONING` classes to the sidebar.\n * 2. The sidebar collapse begins to animate. On desktop devices, and where it\n * is supported, we transition the `grid-template-columns` property of the\n * sidebar layout. On mobile, the sidebar is hidden immediately. In both\n * cases, the collapse icon rotates and we use this rotation to determine\n * when the transition is complete.\n * 3. If another sidebar state toggle is requested while closing the sidebar,\n * we remove the `COLLAPSE` class and the animation immediately starts to\n * reverse.\n * 4. When the `transition` is complete, we remove the `TRANSITIONING` class.\n * @readonly\n * @type {boolean}\n */\n get isClosed(): boolean {\n return this.layout.container.classList.contains(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * Static classes related to the sidebar layout or state.\n * @public\n * @static\n * @readonly\n * @type {{ LAYOUT: string; COLLAPSE: string; TRANSITIONING: string; }}\n */\n public static readonly classes = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n LAYOUT: \"bslib-sidebar-layout\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n COLLAPSE: \"sidebar-collapsed\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n TRANSITIONING: \"transitioning\",\n };\n\n /**\n * If sidebars are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n /**\n * A map of initialized sidebars to their respective Sidebar instances.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Given a sidebar container, return the Sidebar instance associated with it.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Sidebar | undefined)}\n */\n public static getInstance(el: HTMLElement): Sidebar | undefined {\n return Sidebar.instanceMap.get(el);\n }\n\n /**\n * Initialize all collapsible sidebars on the page.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true] When `true`, we remove\n * non-existent elements from the ResizeObserver. This is required\n * periodically to prevent memory leaks. To avoid over-checking, we only flush\n * the ResizeObserver when initializing sidebars after page load.\n */\n public static initCollapsibleAll(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Sidebar.onReadyScheduled) {\n Sidebar.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Sidebar.initCollapsibleAll(false);\n });\n }\n return;\n }\n\n const initSelector = `.${Sidebar.classes.LAYOUT}[data-bslib-sidebar-init]`;\n if (!document.querySelector(initSelector)) {\n // no sidebars to initialize\n return;\n }\n\n if (flushResizeObserver) Sidebar.shinyResizeObserver.flush();\n\n const containers = document.querySelectorAll(initSelector);\n containers.forEach((container) => new Sidebar(container as HTMLElement));\n }\n\n /**\n * Initialize event listeners for the sidebar toggle button.\n * @private\n */\n private _initEventListeners(): void {\n const { toggle } = this.layout;\n\n toggle.addEventListener(\"click\", (ev) => {\n ev.preventDefault();\n this.toggle(\"toggle\");\n });\n\n // Remove the transitioning class when the transition ends. We watch the\n // collapse toggle icon because it's guaranteed to transition, whereas the\n // sidebar doesn't animate on mobile (or in browsers where animating\n // grid-template-columns is not supported).\n toggle\n .querySelector(\".collapse-icon\")\n ?.addEventListener(\"transitionend\", () => this._finalizeState());\n }\n\n /**\n * Initialize nested sidebar counters.\n *\n * @description\n * This function walks up the DOM tree, adding CSS variables to each direct\n * parent sidebar layout that count the layout's position in the stack of\n * nested layouts. We use these counters to keep the collapse toggles from\n * overlapping. Note that always-open sidebars that don't have collapse\n * toggles break the chain of nesting.\n * @private\n */\n private _initSidebarCounters(): void {\n const { container } = this.layout;\n\n const selectorChildLayouts =\n `.${Sidebar.classes.LAYOUT}` +\n \"> .main > \" +\n `.${Sidebar.classes.LAYOUT}:not([data-bslib-sidebar-open=\"always\"])`;\n\n const isInnermostLayout =\n container.querySelector(selectorChildLayouts) === null;\n\n if (!isInnermostLayout) {\n // There are sidebar layouts nested within this layout; defer to children\n return;\n }\n\n function nextSidebarParent(el: HTMLElement | null): HTMLElement | null {\n el = el ? el.parentElement : null;\n if (el && el.classList.contains(\"main\")) {\n // .bslib-sidebar-layout > .main > .bslib-sidebar-layout\n el = el.parentElement;\n }\n if (el && el.classList.contains(Sidebar.classes.LAYOUT)) {\n return el;\n }\n return null;\n }\n\n const layouts = [container];\n let parent = nextSidebarParent(container);\n\n while (parent) {\n // Add parent to front of layouts array, so we sort outer -> inner\n layouts.unshift(parent);\n parent = nextSidebarParent(parent);\n }\n\n const count = { left: 0, right: 0 };\n layouts.forEach(function (x: HTMLElement, i: number): void {\n x.style.setProperty(\"--bslib-sidebar-counter\", i.toString());\n const isRight = x.classList.contains(\"sidebar-right\");\n const thisCount = isRight ? count.right++ : count.left++;\n x.style.setProperty(\n \"--bslib-sidebar-overlap-counter\",\n thisCount.toString()\n );\n });\n }\n\n /**\n * Initialize the sidebar's initial state when `open = \"desktop\"`.\n * @private\n */\n private _initDesktop(): void {\n const { container } = this.layout;\n // If sidebar is marked open='desktop'...\n if (container.dataset.bslibSidebarOpen?.trim() !== \"desktop\") {\n return;\n }\n\n // then close sidebar on mobile\n const initCollapsed = window\n .getComputedStyle(container)\n .getPropertyValue(\"--bslib-sidebar-js-init-collapsed\");\n\n if (initCollapsed.trim() === \"true\") {\n this.toggle(\"close\");\n }\n }\n\n /**\n * Toggle the sidebar's open/closed state.\n * @public\n * @param {SidebarToggleMethod | undefined} method Whether to `\"open\"`,\n * `\"close\"` or `\"toggle\"` the sidebar. If `.toggle()` is called without an\n * argument, it will toggle the sidebar's state.\n */\n public toggle(method: SidebarToggleMethod | undefined): void {\n if (typeof method === \"undefined\") {\n method = \"toggle\";\n }\n\n const { container, sidebar } = this.layout;\n const isClosed = this.isClosed;\n\n if ([\"open\", \"close\", \"toggle\"].indexOf(method) === -1) {\n throw new Error(`Unknown method ${method}`);\n }\n\n if (method === \"toggle\") {\n method = isClosed ? \"open\" : \"close\";\n }\n\n if ((isClosed && method === \"close\") || (!isClosed && method === \"open\")) {\n // nothing to do, sidebar is already in the desired state\n return;\n }\n\n if (method === \"open\") {\n // unhide sidebar immediately when opening,\n // otherwise the sidebar is hidden on transitionend\n sidebar.hidden = false;\n }\n\n // Add a transitioning class just before adding COLLAPSE_CLASS since we want\n // some of the transitioning styles to apply before the collapse state\n container.classList.add(Sidebar.classes.TRANSITIONING);\n container.classList.toggle(Sidebar.classes.COLLAPSE);\n }\n\n /**\n * When the sidebar open/close transition ends, finalize the sidebar's state.\n * @private\n */\n private _finalizeState(): void {\n const { container, sidebar, toggle } = this.layout;\n container.classList.remove(Sidebar.classes.TRANSITIONING);\n sidebar.hidden = this.isClosed;\n toggle.setAttribute(\"aria-expanded\", this.isClosed ? \"false\" : \"true\");\n\n // Send browser-native event with updated sidebar state\n const event = new CustomEvent(\"bslib.sidebar\", {\n bubbles: true,\n detail: { open: !this.isClosed },\n });\n sidebar.dispatchEvent(event);\n\n // Trigger Shiny input and output binding events\n $(sidebar).trigger(\"toggleCollapse.sidebarInputBinding\");\n $(sidebar).trigger(this.isClosed ? \"hidden\" : \"shown\");\n }\n}\n\n/**\n * A Shiny input binding for a sidebar.\n * @class SidebarInputBinding\n * @typedef {SidebarInputBinding}\n * @extends {InputBinding}\n */\nclass SidebarInputBinding extends InputBinding {\n find(scope: HTMLElement) {\n return $(scope).find(`.${Sidebar.classes.LAYOUT} > .bslib-sidebar-input`);\n }\n\n getValue(el: HTMLElement): boolean {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (!sb) return false;\n return !sb.isClosed;\n }\n\n setValue(el: HTMLElement, value: boolean): void {\n const method = value ? \"open\" : \"close\";\n this.receiveMessage(el, { method });\n }\n\n subscribe(el: HTMLElement, callback: (x: boolean) => void) {\n $(el).on(\n \"toggleCollapse.sidebarInputBinding\",\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n function (event) {\n callback(true);\n }\n );\n }\n\n unsubscribe(el: HTMLElement) {\n $(el).off(\".sidebarInputBinding\");\n }\n\n receiveMessage(el: HTMLElement, data: SidebarMessageData) {\n const sb = Sidebar.getInstance(el.parentElement as HTMLElement);\n if (sb) sb.toggle(data.method);\n }\n}\n\nregisterBinding(SidebarInputBinding, \"sidebar\");\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Sidebar = Sidebar;\n"],
+ "mappings": "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",
+ "names": ["InputBinding", "registerBinding", "inputBindingClass", "name", "ShinyResizeObserver", "entries", "resizeEvent", "resized", "entry", "el", "binding", "onResize", "owner", "img", "idxEl", "_Sidebar", "container", "_a", "sideAccordion", "initScript", "el", "flushResizeObserver", "initSelector", "toggle", "ev", "selectorChildLayouts", "nextSidebarParent", "layouts", "parent", "count", "x", "i", "thisCount", "method", "sidebar", "isClosed", "event", "Sidebar", "ShinyResizeObserver", "SidebarInputBinding", "InputBinding", "scope", "sb", "value", "callback", "data", "registerBinding"]
}
diff --git a/inst/components/scss/sidebar.scss b/inst/components/scss/sidebar.scss
index 9628a1a96..f5804f7a7 100644
--- a/inst/components/scss/sidebar.scss
+++ b/inst/components/scss/sidebar.scss
@@ -1,20 +1,30 @@
$bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0,0,0), 0.05) !default;
$bslib-sidebar-fg: var(--bs-emphasis-color, black) !default;
+$bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0,0,0), 0.1) !default;
$bslib-sidebar-border: var(--bs-card-border-width, #{$card-border-width}) solid var(--bs-card-border-color, #{$card-border-color}) !default;
$bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)), var(--bslib-sidebar-width, 250px));
.bslib-sidebar-layout {
--bslib-sidebar-transition-duration: 500ms;
+ --bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);
--bslib-sidebar-border: #{$bslib-sidebar-border};
--bslib-sidebar-border-radius: var(--bs-border-radius);
--bslib-sidebar-vert-border: #{$bslib-sidebar-border};
--bslib-sidebar-bg: #{$bslib-sidebar-bg};
--bslib-sidebar-fg: #{$bslib-sidebar-fg};
+ --bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));
+ --bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));
+ --bslib-sidebar-toggle-bg: #{$bslib-sidebar-toggle-bg};
--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);
--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);
- --bslib-collapse-toggle-border: #{$bslib-sidebar-border};
- --bslib-collapse-toggle-transform: 90deg;
- --bslib-collapse-toggle-right-transform: -90deg;
+ --bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);
+ --bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);
+ // We intentionally don't give a value here, but it could be set by someone else
+ // --bslib-collapse-toggle-border: ;
+ --bslib-collapse-toggle-border-radius: var(--bs-border-radius, #{$border-radius});
+ --bslib-collapse-toggle-transform: 0deg;
+ --bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);
+ --bslib-collapse-toggle-right-transform: 180deg;
--bslib-sidebar-column-main: minmax(0, 1fr);
@@ -45,6 +55,9 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
border-top-left-radius: 0;
border-bottom-left-radius: 0;
padding: var(--bslib-sidebar-padding);
+ transition: padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);
+ color: var(--bslib-sidebar-main-fg);
+ background-color: var(--bslib-sidebar-main-bg);
}
> .sidebar {
@@ -54,14 +67,17 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
border-right: var(--bslib-sidebar-vert-border);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
- background-color: var(--bslib-sidebar-bg);
color: var(--bslib-sidebar-fg);
+ background-color: var(--bslib-sidebar-bg);
+ backdrop-filter: blur(5px);
> .sidebar-content {
display: flex;
flex-direction: column;
gap: var(--bslib-spacer, 1rem);
padding: var(--bslib-sidebar-padding);
+ // Add space for the toggle button (removed if sidebar is always open)
+ padding-top: var(--bslib-sidebar-padding-icon);
> :last-child:not(.sidebar-title) {
// Remove margin-bottom from the last item because sidebar has padding.
@@ -73,9 +89,6 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
> .accordion {
margin-left: calc(-1 * var(--bslib-sidebar-padding));
margin-right: calc(-1 * var(--bslib-sidebar-padding));
- &:first-child {
- margin-top: calc(-1 * var(--bslib-sidebar-padding));
- }
&:last-child {
margin-bottom: calc(-1 * var(--bslib-sidebar-padding));
}
@@ -99,17 +112,9 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
border-bottom: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);
}
- // When a sidebar title appears just above an accordion, we use the
- // accordion's top border as the "underline". The fiddly margin-top bit
- // adjusts the accordion to cover the title bottom border in browsers
- // that don't yet support :has().
- // TODO: this can be removed once :has() has better browser support
- > .sidebar-title + .accordion {
- margin-top: calc(-#{$spacer} - var(--bs-card-border-width, #{$card-border-width}));
- }
-
- > .sidebar-title:has(+ .accordion) {
+ &.has-accordion > .sidebar-title {
border-bottom: none;
+ padding-bottom: 0;
}
}
@@ -118,30 +123,49 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
}
}
+ &[data-bslib-sidebar-open="always"] {
+ > .sidebar > .sidebar-content {
+ // Always-open sidebars don't have a toggle & can use normal top padding
+ padding-top: var(--bslib-sidebar-padding);
+ }
+ }
+
> .collapse-toggle {
grid-row: 1 / 2;
grid-column: 1 / 2;
display: inline-flex;
align-items: center;
position: absolute;
- right: calc(-1 * var(--bslib-sidebar-icon-size));
- // The CSS variable (set via JS) is here to help avoid overlapping toggles
- bottom: calc(var(--bslib-sidebar-padding) + var(--bslib-sidebar-overlap-counter, 0) * calc(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)));
- border: var(--bslib-collapse-toggle-border);
- border-left: none;
- border-radius: 0 var(--bs-border-radius) var(--bs-border-radius) 0;
- padding: 7px 0;
- background-color: var(--bslib-sidebar-bg);
+ right: calc(var(--bslib-sidebar-icon-size));
+ top: calc(var(--bslib-sidebar-icon-size, 1rem) / 2);
+ border: none;
+ border-radius: var(--bslib-collapse-toggle-border-radius);
+ height: var(--bslib-sidebar-icon-button-size, 2rem);
+ width: var(--bslib-sidebar-icon-button-size, 2rem);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
color: var(--bslib-sidebar-fg);
+ background-color: unset; // don't take `button` background color
+ transition:
+ color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),
+ top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),
+ right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),
+ left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);
+
+ &:hover {
+ background-color: var(--bslib-sidebar-toggle-bg);
+ }
> .collapse-icon {
opacity: 0.8;
width: var(--bslib-sidebar-icon-size);
height: var(--bslib-sidebar-icon-size);
- transform: rotate(var(--bslib-collapse-toggle-transform));
+ transform: rotateY(var(--bslib-collapse-toggle-transform));
// N.B. since mobile view won't trigger a transition of grid-template-columns,
// we transition this toggle to ensure _some_ transition event always happens.
- transition: transform cubic-bezier(0.68, -0.55, 0.27, 1.55) var(--bslib-sidebar-transition-duration);
+ transition: transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration);
}
&:hover > .collapse-icon {
@@ -179,20 +203,18 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
> .collapse-toggle {
grid-column: 2 / 3;
- left: calc(-1 * var(--bslib-sidebar-icon-size));
+ left: var(--bslib-sidebar-icon-size);
right: unset;
- border-radius: var(--bs-border-radius) 0 0 var(--bs-border-radius);
- border-right: none;
- border-left: var(--bslib-collapse-toggle-border);
+ border: var(--bslib-collapse-toggle-border);
> .collapse-icon {
- transform: rotate(var(--bslib-collapse-toggle-right-transform));
+ transform: rotateY(var(--bslib-collapse-toggle-right-transform));
}
}
}
&.sidebar-collapsed {
- --bslib-collapse-toggle-transform: -90deg;
- --bslib-collapse-toggle-right-transform: 90deg;
+ --bslib-collapse-toggle-transform: 180deg;
+ --bslib-collapse-toggle-right-transform: 0deg;
--bslib-sidebar-vert-border: none;
grid-template-columns: 0 minmax(0, 1fr);
@@ -215,12 +237,26 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
border-radius: inherit;
}
+ &:not(.sidebar-right) > .main {
+ padding-left: var(--bslib-sidebar-padding-icon);
+ }
+ &.sidebar-right > .main {
+ padding-right: var(--bslib-sidebar-padding-icon);
+ }
+
> .collapse-toggle {
- right: calc(-1 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));
+ color: var(--bslib-sidebar-main-fg);
+ // The CSS variable (set via JS) is here to help avoid overlapping toggles
+ top: calc(
+ var(--bslib-sidebar-overlap-counter, 0) *
+ calc(var(--bslib-sidebar-icon-size) +
+ var(--bslib-sidebar-padding)
+ ) + var(--bslib-sidebar-icon-size, 1rem) / 2);
+ right: calc(-2.5 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));
}
&.sidebar-right > .collapse-toggle {
- left: calc(-1 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));
+ left: calc(-2.5 * var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));
right: unset;
}
}
@@ -235,90 +271,71 @@ $bslib-sidebar-column-sidebar: Min(calc(100% - var(--bslib-sidebar-icon-size)),
}
@include media-breakpoint-down(sm) {
- .bslib-sidebar-layout, .bslib-sidebar-layout.sidebar-right {
- --bslib-sidebar-vert-border: none;
- --bslib-sidebar-horiz-border: #{$bslib-sidebar-border};
- --bslib-collapse-toggle-transform: -180deg;
- --bslib-collapse-toggle-right-transform: -180deg;
-
- // required by sidebar init js when `sidebar(open = "desktop")`
+ .bslib-sidebar-layout {
+ // Tell sidebar init js we're on mobile for `sidebar(open = "desktop")`
&[data-bslib-sidebar-open="desktop"] {
--bslib-sidebar-js-init-collapsed: true;
}
- grid-template-columns: 1fr !important;
- // Sidebar height is constrained on mobile where upper bound is determined
- // by bslib UI functions. The minimax() is important to ensure the main main
- // content is allowed to grow/shrink.
- grid-template-rows:
- fit-content(var(--bslib-sidebar-max-height-mobile, auto))
- minmax(0, 1fr);
-
- > .sidebar {
- grid-row: 1 / 2;
- grid-column: 1 / 2;
- width: 100%;
- border: none;
- border-bottom: var(--bslib-sidebar-horiz-border);
- border-radius: 0;
- }
+ &, &.sidebar-right {
+ // Remove sidebar borders in mobile view (except always-open, added below)
+ > .sidebar { border: none }
- > .main {
- grid-row: 2 / 3;
- grid-column: 1 / 2;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- border-bottom-right-radius: inherit;
- border-bottom-left-radius: inherit;
+ // Main area takes up entire layout area to avoid layout shift when
+ // sidebar is expanded as an overlay.
+ > .main {
+ grid-column: 1 / 3;
+ }
}
- > .collapse-toggle {
- grid-row: 2 / 3;
- grid-column: 1 / 2;
- border-top: none !important;
- border: var(--bslib-collapse-toggle-border);
- border-radius: 0 0 var(--bs-border-radius) var(--bs-border-radius);
- padding: 0 4px;
- > .collapse-icon {
- // On mobile we can transition the icon orientation immediately and quickly
- transition-duration: calc(var(--bslib-sidebar-transition-duration) * 0.33);
+ // Always open sidebars become "flow" layouts in mobile view
+ &[data-bslib-sidebar-open="always"] {
+ display: block !important;
+ > .sidebar {
+ max-height: var(--bslib-sidebar-max-height-mobile);
+ overflow-y: auto;
+ border-top: var(--bslib-sidebar-vert-border);
}
}
- // Apply same collapse-toggle position adjustment to all states and layouts
- &, &.sidebar-right {
- > .collapse-toggle {
- top: calc(-1 * var(--bs-card-border-width, 1px));
+ &:not([data-bslib-sidebar-open="always"]) {
+ // Sidebar layer has to be lifted up to cover other (nested) sidebars
+ &:not(.sidebar-collapsed) {
+ > .sidebar { z-index: 1; }
+ > .collapse-toggle { z-index: 1; }
}
- &.sidebar-collapsed > .collapse-toggle {
- top: 0;
+
+ // Either sidebar or main area take up entire layout depending on state
+ $full-closed: 100% 0;
+ $closed-full: 0 100%;
+ grid-template-columns: $full-closed;
+ &.sidebar-right {
+ grid-template-columns: $closed-full;
}
- &, &.sidebar-collapsed {
- > .collapse-toggle {
- // The CSS variable (set via JS) is here to help avoid overlapping toggles
- right: calc(var(--bslib-sidebar-padding) + var(--bslib-sidebar-counter, 0) * calc(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)));
- bottom: initial;
- left: initial;
+
+ &.sidebar-collapsed {
+ grid-template-columns: $closed-full;
+ &.sidebar-right {
+ grid-template-columns: $full-closed;
}
}
- }
- &.sidebar-collapsed {
- --bslib-collapse-toggle-transform: 0deg;
- --bslib-collapse-toggle-right-transform: 0deg;
- grid-template-rows: 0 minmax(0, 1fr);
- // TODO: according to the spec, grid-template-rows should be animatable,
- // but this doesn't behave quite right, and I'm not sure why
- // transition: grid-template-rows ease-in-out var(--bslib-sidebar-transition-duration);
+ // Keep padding on main contents when sidebar is expanded (avoid shifts)
+ &:not(.sidebar-right) > .main {
+ padding-left: var(--bslib-sidebar-padding-icon);
+ }
+ &.sidebar-right > .main {
+ padding-right: var(--bslib-sidebar-padding-icon);
+ }
+ // Make main contents transparent while sidebar is expanded
> .main {
- border-top-left-radius: inherit;
- border-top-right-radius: inherit;
+ opacity: 0;
+ transition: opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)
}
-
- > .sidebar {
- border-bottom: none;
+ &.sidebar-collapsed > .main {
+ opacity: 1;
}
}
}
diff --git a/man/sidebar.Rd b/man/sidebar.Rd
index a53636b03..44dc491a6 100644
--- a/man/sidebar.Rd
+++ b/man/sidebar.Rd
@@ -82,10 +82,11 @@ color, e.g. setting \code{bg} chooses an appropriate \code{fg} color.}
\item{class}{CSS classes for the sidebar container element, in addition to
the fixed \code{.sidebar} class.}
-\item{max_height_mobile}{The maximum height of the horizontal sidebar when
-viewed on mobile devices. The default is \verb{250px} unless the sidebar is
-included in a \code{\link[=layout_sidebar]{layout_sidebar()}} with a specified height, in which case
-the default is to take up no more than 50\% of the layout container.}
+\item{max_height_mobile}{A \link[htmltools:validateCssUnit]{CSS length unit}
+defining the maximum height of the horizontal sidebar when viewed on mobile
+devices. Only applies to always-open sidebars that use \code{open = "always"},
+where by default the sidebar container is placed below the main content
+container on mobile devices.}
\item{gap}{A \link[htmltools:validateCssUnit]{CSS length unit} defining the
vertical \code{gap} (i.e., spacing) between adjacent elements provided to \code{...}.}
diff --git a/srcts/src/components/sidebar.ts b/srcts/src/components/sidebar.ts
index c23fcce36..ae5c11357 100644
--- a/srcts/src/components/sidebar.ts
+++ b/srcts/src/components/sidebar.ts
@@ -93,6 +93,8 @@ class Sidebar {
":scope > .sidebar-content > .accordion"
);
if (sideAccordion) {
+ // Add `.has-accordion` class to `.sidebar-content` container
+ sideAccordion?.parentElement?.classList.add("has-accordion");
sideAccordion.classList.add("accordion-flush");
}
diff --git a/tests/testthat/_snaps/page.md b/tests/testthat/_snaps/page.md
index 845fa5557..4a85ab9e7 100644
--- a/tests/testthat/_snaps/page.md
+++ b/tests/testthat/_snaps/page.md
@@ -55,7 +55,7 @@