rstudio / bslib

Tools for theming Shiny and R Markdown via Bootstrap 3, 4, or 5.
https://rstudio.github.io/bslib/
Other
443 stars 50 forks source link

Exit full-screen mode when a full-screen card is removed #1005

Closed gadenbuie closed 4 months ago

gadenbuie commented 4 months ago

Fixes #1003

Adds a new ShinyRemovedObserver class that's conceptually similar to ShinyResizeObserver but instead calls a callback function on matching elements when they're removed from the DOM.

In this case, we instantiate a static cardRemovedObserver on the Card class that watches the ~card's parent element~ the document.body for changes and exits full screen mode when a full-screen card is removed.

Note that we can't watch the parent element because the card might be in a layout_columns() in a renderUI() (this is pretty common). The ShinyRemovedObserver is careful to do as little work as needed to find the matching elements, and I think the abstraction is still worth it. We might want to use it in other places and the callback in the Card class is easier to read and understand without the boilerplate of MutationObserver.

Example app

This example app contains a card that is dynamically rendered inside a renderUI(). When the card is modified in full screen mode, the currently-full-screen card is removed from the DOM and replaced with a new card (or not replaced at all, it's dynamic UI!).

Previously, we were not cleaning up the full screen state when a full-screen card was removed. Now, we see the old, full-screen card was removed and we call the exit full screen methods to reset the full screen state.

library(shiny)
library(bslib)

choices <- c("cyl", "disp")

ui <- page_fixed(
  uiOutput("content")
)

server <- function(input, output) {
  output$content <- renderUI({
    layout_columns(
      card(
        card_header("Marker:", input$marker),
        selectInput(
          "marker",
          "Marker:",
          choices = choices,
          selected = input$marker
        ),
        full_screen = TRUE,
        min_height = 300
      )
    )
  })
}

shinyApp(ui = ui, server = server)