Appsilon / shiny.emptystate

Empty state components for Shiny
https://appsilon.github.io/shiny.emptystate/
27 stars 2 forks source link

Bugfix/32 #42

Open Eduardodudu opened 1 year ago

Eduardodudu commented 1 year ago

Have you read the Contributing Guidelines?

Issue #32

Changes description

  1. Created a new js function shiny_emptystate_updatePosition that updates the position of the empty container when the selected tag id is triggered

Example:

shiny::shinyApp(
    ui = bslib::page(
      theme = bslib::bs_theme(version = 5),
      use_empty_state(),
      shiny::actionButton(
        "toggle_pannel",
        "Toggle panel",
        class = "btn btn-primary",
        onClick = "$('#container1').toggle(anim = 'slide', function(){shiny_emptystate_updatePosition('container2')});"
      ),
      shiny::div(
        style = "width: 300px",
        class = "d-flex flex-column gap-5",
        shiny::div(
          id = "container1",
          shiny::div(
            shiny::h1("Card 1"),
            "Card content"
          )
        ),
        shiny::div(
          id = "container2",
          shiny::div(
            shiny::h1("Card 2"),
            "Card content"
          )
        )
      )
    ),
    server = function(input, output) {
      empty_state_content <- shiny::div(
        "This is example empty state content"
      )
      empty_state_manager <- EmptyStateManager$new(
        id = "container2",
        html_content = empty_state_content
      )
      empty_state_manager$show()
    }
  )

Clearly and concisely describe what's in this pull request. Include screenshots, if necessary.

Eduardodudu commented 1 year ago

Approaches I tried before this bugfix

These were two approaches I tried by using an observer event to trigger an update of the emptyStateContainer to follow along the animation slider. These approaches didn't work and I ended up using the after animation slide approach.

IntersectionObserver with getBoundingClientRect

//create the intersection observer
const intersectionObserver = new IntersectionObserver((entries) => {

  entries.forEach(entry => {
    const emptyStateContainer = entry.target.querySelector(".empty-state-container");
    const rect = entry.target.getBoundingClientRect();
    const isVisible = entry.isIntersecting;

    if (isVisible) {
      emptyStateContainer.style.height = rect.offsetHeight + "px";
      emptyStateContainer.style.width = rect.offsetWidth + "px";
      emptyStateContainer.style.left = rect.offsetLeft + "px";
      emptyStateContainer.style.top = rect.offsetTop + "px";
      console.log(emptyStateContainer.style);
      console.log(rect.style);
    }
  });
}, {
  root: null,
  rootMargin: '0px',
  threshold: 1.0 // Fully visible
});

//use it on the show and hide methods
function showEmptyState(message) {
 // ....
  intersectionObserver.observe(elementToReplace);
}

function hideEmptyState(message) {
    // ...
  intersectionObserver.unobserve(elementToReplace);
}

Using MutationObserver

// ...

function showEmptyState(message) {
    //...
  intersectionObserver.observe(elementToReplace);
  observeDOMChanges(elementToReplace);
}

function repositionEmptyState() {
  const emptyStateContainers = document.querySelectorAll(".empty-state-container");

  emptyStateContainers.forEach(emptyStateContainer => {
    const parentElement = emptyStateContainer.parentElement;
    emptyStateContainer.style.height = parentElement.offsetHeight + "px";
    emptyStateContainer.style.width = parentElement.offsetWidth + "px";
    emptyStateContainer.style.left = parentElement.offsetLeft + "px";
    emptyStateContainer.style.top = parentElement.offsetTop + "px";
  });
}

function observeDOMChanges(elementToReplace) {
  const targetNode = elementToReplace;

  const mutationObserver = new MutationObserver(mutationsList => {
    repositionEmptyState();
  });

  const config = { attributes: true, childList: true, subtree: true };

  mutationObserver.observe(targetNode, config);
}
codecov-commenter commented 1 year ago

Codecov Report

Merging #42 (cd2f3e3) into main (6b5cf59) will not change coverage. The diff coverage is n/a.

:exclamation: Your organization needs to install the Codecov GitHub app to enable full functionality.

@@            Coverage Diff            @@
##              main       #42   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines           45        45           
=========================================
  Hits            45        45