Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/32 #42

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Bugfix/32 #42

wants to merge 10 commits into from

Conversation

Eduardodudu
Copy link

@Eduardodudu Eduardodudu commented Aug 1, 2023

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
Copy link
Author

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);
}

@Eduardodudu Eduardodudu marked this pull request as ready for review August 2, 2023 23:42
Copy link
Member

@jakubnowicki jakubnowicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty state component that follows the element that should be hidden looks bad.
shiny_emptystate

The documentation is missing.

Comment on lines 60 to 67
it("checks the empty state component follows slider from id", {
app <- shinytest2::AppDriver$new(test_slider_app(), name = "slide_tag")
app$expect_values()
app$click("toggle_pannel")
app$expect_values()
app$stop()
})
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is useless.

  1. You have not included the snapshots generated by app$expected_values(), so the tests are not run against the reference, they only generate references.
  2. Even with the snapshots, this test only verifies the values of inputs and outputs, which means that the only thing that you test is if the button was clicked. You are not testing the position of the empty state container.

@codecov-commenter
Copy link

codecov-commenter commented Sep 28, 2023

Codecov Report

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

❗ 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           

Copy link
Member

@jakubnowicki jakubnowicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check my comments.


The example below showcases the example of using a dynamic trigger slider that changes.

The function `shiny_emptystate_updatePosition` updates the position of the #container1 after being re-positioned
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make it clear that this function is 1. JS 2. comes withshiny.emptystate.

@@ -75,6 +75,18 @@ function hideEmptyState(message) {
resizeObserver.unobserve(elementToReplace);
}

function shiny_emptystate_updatePosition(id){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change the name of the function to follow camel case, instead of a weird hybrid. updateElementPosition should work here.


# Introduction

`shiny.emptystate` is capable of being used for dynamic positioning trigger animations. This is specially interesting when we have UIs that change position and we want to keep the `emptystate` in the appropriate tag
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`shiny.emptystate` is capable of being used for dynamic positioning trigger animations. This is specially interesting when we have UIs that change position and we want to keep the `emptystate` in the appropriate tag
`shiny.emptystate` is capable of being used for dynamic positioning trigger animations. This is specially useful when we have UIs that change position and we want to keep the `emptystate` in the appropriate tag


# Animation example

The example below showcases the example of using a dynamic trigger slider that changes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain this in more detail. Also, inform the reader what would happen without the updatePosition function.

- icon: fa-file-code-o
href: index.html
tutorials:
text: Tutorials
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new article is not a tutorial, but a small guide. Change this to "Articles".


it("checks the empty state component follows slider from id", {
app <- shinytest2::AppDriver$new(test_slider_app(), name = "slide_tag")
position_1 <- app$get_html(selector = "#container2")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a position, but a full HTML. The variable name is misleading.

app <- shinytest2::AppDriver$new(test_slider_app(), name = "slide_tag")
position_1 <- app$get_html(selector = "#container2")
app$click("toggle_pannel")
position_2 <- app$get_html(selector = "#container2")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a position, but a full HTML. The variable name is misleading.

position_1 <- app$get_html(selector = "#container2")
app$click("toggle_pannel")
position_2 <- app$get_html(selector = "#container2")
expect_false(position_1 == position_2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you compare the whole HTML, this may be a false positive (some other parts of HTML will change).


`shiny.emptystate` is capable of being used for dynamic positioning trigger animations. This is specially interesting when we have UIs that change position and we want to keep the `emptystate` in the appropriate tag

**Note:** This solution is only available for instant positioning animation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please include the solution for the animations, provided in the issue comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants