diff --git a/R/data-apps-deps.R b/R/data-apps-deps.R index 618dee6538..d69d8d3193 100644 --- a/R/data-apps-deps.R +++ b/R/data-apps-deps.R @@ -60,4 +60,5 @@ apps_deps_map <- list(`001-hello` = "rsconnect", `012-datatables` = "ggplot2", "rversions"), `305-bslib-value-box` = c("rlang", "rversions" ), `309-flexdashboard-tabs-navs` = "rmarkdown", `310-bslib-sidebar-dynamic` = c("rversions", "testthat"), `311-bslib-sidebar-toggle-methods` = c("rversions", - "testthat")) + "testthat"), `313-bslib-card-tab-focus` = c("rversions", + "testthat", "withr")) diff --git a/inst/apps/311-bslib-sidebar-toggle-methods/app.R b/inst/apps/311-bslib-sidebar-toggle-methods/app.R index 36b1dbb3cd..f2f0003886 100644 --- a/inst/apps/311-bslib-sidebar-toggle-methods/app.R +++ b/inst/apps/311-bslib-sidebar-toggle-methods/app.R @@ -17,59 +17,57 @@ animals <- c( "otter", "panda", "panther", "penguin", "zebra" ) -sb <- layout_column_wrap( - width = 500, - id = "sidebar-here", - layout_sidebar( - id = "main_outer", - sidebar = sidebar( - "Outer Sidebar", - id = "sidebar_outer", - width = 150, - bg = color_pairs[[1]]$dark, - open = "desktop", - max_height_mobile = "300px", - selectInput( - "adjective", - "Adjective", - choices = adjectives, - selected = adjectives[1] - ) - ), - height = 300, - class = "p-0", - fillable = TRUE, +ui <- page_fixed( + h1("Dynamic Sidebars"), + tags$head(tags$title("bslib | Tests | Dynamic Sidebars")), + p( + "Test tab focus order: main, inner sidebar, outer sidebar.", + "Test server-side open and close of sidebars." + ), + layout_column_wrap( + width = 500, + id = "sidebar-here", layout_sidebar( - id = "main_inner", + id = "main_outer", sidebar = sidebar( - "Inner Sidebar", - id = "sidebar_inner", + "Outer Sidebar", + id = "sidebar_outer", width = 150, - bg = color_pairs[[1]]$light, + bg = color_pairs[[1]]$dark, open = "desktop", + max_height_mobile = "300px", selectInput( - "animal", - "Animal", - choices = animals, - selected = animals[1] + "adjective", + "Adjective", + choices = adjectives, + selected = adjectives[1] ) ), - border = FALSE, - border_radius = FALSE, - h2("Sidebar Layout"), - uiOutput("ui_content", tabindex = 0) + height = 300, + class = "p-0", + fillable = TRUE, + layout_sidebar( + id = "main_inner", + sidebar = sidebar( + "Inner Sidebar", + id = "sidebar_inner", + width = 150, + bg = color_pairs[[1]]$light, + open = "desktop", + selectInput( + "animal", + "Animal", + choices = animals, + selected = animals[1] + ) + ), + border = FALSE, + border_radius = FALSE, + h2("Sidebar Layout"), + uiOutput("ui_content", tabindex = 0), + ) ) - ) -) - -ui <- page_fixed( - h1("Dynamic Sidebars"), - tags$head(tags$title("bslib | Tests | Dynamic Sidebars")), - p( - "Test tab focus order: main, inner sidebar, outer sidebar.", - "Test server-side open and close of sidebars." ), - tagAppendAttributes(sb, class = "mb-4", id = "layout"), div( class = "my-2", actionButton("show_all", "Show all"), diff --git a/inst/apps/311-bslib-sidebar-toggle-methods/tests/testthat/test-shinytest2.R b/inst/apps/311-bslib-sidebar-toggle-methods/tests/testthat/test-shinytest2.R index 8ecda4ebca..55fb6f4283 100644 --- a/inst/apps/311-bslib-sidebar-toggle-methods/tests/testthat/test-shinytest2.R +++ b/inst/apps/311-bslib-sidebar-toggle-methods/tests/testthat/test-shinytest2.R @@ -12,58 +12,7 @@ is_mac_release <- identical(paste0("mac-", release), platform_variant()) DO_SCREENSHOT <- is_testing_on_ci && is_mac_release -key_press_factory <- function(app) { - brwsr <- app$get_chromote_session() - - function(which = "Tab", shift = FALSE) { - virtual_code <- switch( - which, - Tab = 9, - Enter = 13, - Escape = 27, - ArrowLeft = 37, - ArrowUp = 38, - ArrowRight = 39, - ArrowDown = 40, - Backspace = 8, - Delete = 46, - Home = 36, - End = 35, - PageUp = 33, - PageDown = 34, - Space = 32 - ) - - modifiers <- 0 - if (shift) modifiers <- modifiers + 8 - # if (command) modifiers <- modifiers + 4 - # if (control) modifiers <- modifiers + 2 - # if (alt) modifiers <- modifiers + 1 - - events <- - brwsr$Input$dispatchKeyEvent( - "rawKeyDown", - windowsVirtualKeyCode = virtual_code, - code = which, - key = which, - modifiers = modifiers, - wait_ = FALSE - )$then( - brwsr$Input$dispatchKeyEvent( - "keyUp", - windowsVirtualKeyCode = virtual_code, - code = which, - key = which, - modifiers = modifiers, - wait_ = FALSE - ) - ) - - brwsr$wait_for(events) - - invisible(app) - } -} +source(system.file("helpers", "keyboard.R", package = "shinycoreci")) expect_sidebar_hidden_factory <- function(app) { function(which = c("inner", "outer")) { diff --git a/inst/apps/313-bslib-card-tab-focus/README.md b/inst/apps/313-bslib-card-tab-focus/README.md new file mode 100644 index 0000000000..1dc94b8997 --- /dev/null +++ b/inst/apps/313-bslib-card-tab-focus/README.md @@ -0,0 +1,3 @@ +## 313-bslib-card-tab-focus + +`313-bslib-card-tab-focus` tests the tab focus order of full screen cards. diff --git a/inst/apps/313-bslib-card-tab-focus/app.R b/inst/apps/313-bslib-card-tab-focus/app.R new file mode 100644 index 0000000000..be92eacccc --- /dev/null +++ b/inst/apps/313-bslib-card-tab-focus/app.R @@ -0,0 +1,65 @@ +library(shiny) +library(bslib) + +ui <- page_fixed( + h1("Dynamic Sidebars"), + tags$head(tags$title("bslib | Tests | Dynamic Sidebars")), + div(id = "neutral-focus-zone", tabindex = "-1"), + layout_column_wrap( + width = 1 / 2, + card( + id = "card-no-inputs", + full_screen = TRUE, + card_header("Nothing to focus on here"), + shiny::p( + "This is a boring card with just some plain text.", + "There's something to read here but there aren't any inputs to focus on.", + "Tabbing will only move focus to the \"Close\" button." + ) + ), + card( + id = "card-with-inputs", + full_screen = TRUE, + card_header("Inputs, oh my!"), + shiny::p( + "Here's a bit of text! This card does have stuff to focus on, and the", + "first focusable element is automatically focused when the card is expanded.", + "Try tabbing through the inputs, you can't leave!" + ), + layout_column_wrap( + width = "200px", + class = "mb-3", + card( + id = "card-with-inputs-left", + full_screen = TRUE, + card_title("Left Column", class = "mb-3"), + shiny::selectInput("letter", "Letter", letters, selected = "a"), + shiny::selectizeInput("letter2", "Letter 2", letters, selected = "b", multiple = TRUE), + shiny::dateRangeInput("dates", "Pick a Date") + ), + card( + id = "card-with-inputs-right", + full_screen = TRUE, + card_title("Right Column", class = "mb-3"), + shiny::sliderInput("slider", "Pick a Number", min = 1, max = 10, value = 5), + shiny::textInput("word", "Word", "hello"), + shiny::textAreaInput("sentence", "Sentence", "hello world") + ) + ), + shiny::actionButton("go", "Go") + ), + card( + id = "card-with-plot", + full_screen = TRUE, + card_header("A plotly plot"), + textInput("search", "Search", "search or something"), + plotly::plot_ly(x = rnorm(1e4), y = rnorm(1e4)) + ) + ) +) + +server <- function(input, output, session) { + # no server logic +} + +shinyApp(ui, server) diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat.R b/inst/apps/313-bslib-card-tab-focus/tests/testthat.R new file mode 100644 index 0000000000..7d25b5b9e4 --- /dev/null +++ b/inst/apps/313-bslib-card-tab-focus/tests/testthat.R @@ -0,0 +1 @@ +shinytest2::test_app() diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-001.png b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-001.png new file mode 100644 index 0000000000..599f9f74e4 Binary files /dev/null and b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-001.png differ diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-002.png b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-002.png new file mode 100644 index 0000000000..196834eb74 Binary files /dev/null and b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-002.png differ diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-003.png b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-003.png new file mode 100644 index 0000000000..f3e0690af4 Binary files /dev/null and b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-003.png differ diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-004.png b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-004.png new file mode 100644 index 0000000000..c68443413e Binary files /dev/null and b/inst/apps/313-bslib-card-tab-focus/tests/testthat/_snaps/mac-4.3/313-bslib-card-tab-focus/313-bslib-card-tab-focus-004.png differ diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/setup-shinytest2.R b/inst/apps/313-bslib-card-tab-focus/tests/testthat/setup-shinytest2.R new file mode 100644 index 0000000000..be65b4f035 --- /dev/null +++ b/inst/apps/313-bslib-card-tab-focus/tests/testthat/setup-shinytest2.R @@ -0,0 +1,2 @@ +# Load application support files into testing environment +shinytest2::load_app_env() diff --git a/inst/apps/313-bslib-card-tab-focus/tests/testthat/test-313-bslib-card-tab-focus.R b/inst/apps/313-bslib-card-tab-focus/tests/testthat/test-313-bslib-card-tab-focus.R new file mode 100644 index 0000000000..08fc19e0a7 --- /dev/null +++ b/inst/apps/313-bslib-card-tab-focus/tests/testthat/test-313-bslib-card-tab-focus.R @@ -0,0 +1,360 @@ +library(shinytest2) + +# Only take screenshots on mac + r-release to reduce diff noise +release <- rversions::r_release()$version +release <- paste0( + strsplit(release, ".", fixed = TRUE)[[1]][1:2], + collapse = "." +) + +is_testing_on_ci <- identical(Sys.getenv("CI"), "true") && testthat::is_testing() +is_mac_release <- identical(paste0("mac-", release), platform_variant()) + +DO_SCREENSHOT <- is_testing_on_ci && is_mac_release + +source(system.file("helpers", "keyboard.R", package = "shinycoreci")) + +expect_focus <- function(app, selector) { + js <- sprintf( + "document.activeElement == document.querySelector('%s')", + selector + ) + expect_true(app$get_js(!!js)) + invisible(app) +} + +expect_card_full_screen <- function(app, id) { + id <- sub("^#", "", id) + app$wait_for_js('document.body.matches(".bslib-has-full-screen")') + expect_equal( + app$get_js('document.querySelector(".bslib-full-screen").id'), + id + ) + expect_equal( + app$get_js("document.querySelectorAll('.bslib-full-screen').length"), + 1 + ) + expect_equal( + app$get_js("document.querySelectorAll('#bslib-full-screen-overlay').length"), + 1 + ) + + interior_focus <- app$get_js( + sprintf("document.getElementById('%s').contains(document.activeElement)", id) + ) + if (interior_focus) { + # yeah this doesn't do anything but count the interior focus expectation + expect_true(interior_focus) + } else { + expect_focus(app, paste0("#", id)) + } + invisible(app) +} + +expect_no_full_screen <- function(app) { + app$wait_for_js('!document.body.matches(".bslib-has-full-screen")') + expect_equal( + app$get_js("document.querySelectorAll('.bslib-full-screen').length"), + 0 + ) + invisible(app) +} + +app_reset_no_full_screen <- function(app) { + # reset focus to "neutral focus zone" (just an uninvolved element) + withr::defer(app$run_js("document.getElementById('neutral-focus-zone').focus()")) + + is_full_screen <- app$get_js("document.body.matches('.bslib-has-full-screen')") + + if (!is_full_screen) { + return(invisible(app)) + } + + app$ + click(selector = "#bslib-full-screen-overlay")$ + wait_for_js('!document.body.matches(".bslib-has-full-screen")') +} + +app_card_full_screen_enter <- function(app, id) { + id <- sub("^#", "", id) + app$click(selector = sprintf("#%s > .bslib-full-screen-enter", id)) + expect_card_full_screen(app, id) + invisible(app) +} + +app_card_full_screen_exit <- function( + app, + method = c("click button", "click overlay", "escape", "enter button", "space button") +) { + key_press <- key_press_factory(app) + + method <- match.arg(method) + switch(method, + "click button" = app$click(selector = ".bslib-full-screen-exit"), + "click overlay" = app$click(selector = "#bslib-full-screen-overlay"), + "escape" = key_press("Escape"), + "enter button" = { + app$run_js("document.querySelector('.bslib-full-screen-exit').focus()") + key_press("Enter") + }, + "space button" = { + app$run_js("document.querySelector('.bslib-full-screen-exit').focus()") + key_press("Space") + } + ) + + expect_no_full_screen(app) + invisible(app) +} + +js_computed_display <- function(selector) { + sprintf( + "window.getComputedStyle(document.querySelector('%s')).display", + selector + ) +} + +expect_display <- function(app, value, selector) { + expect_equal(app$get_js(!!js_computed_display(selector)), value) + invisible(app) +} + +# Setup App ----------------------------------------------------------- +app <- AppDriver$new( + name = "313-bslib-card-tab-focus", + variant = platform_variant(), + height = 800, + width = 1200, + seed = 20230517, + view = interactive(), + options = list(bslib.precompiled = FALSE), + expect_values_screenshot_args = FALSE, + screenshot_args = list(selector = "viewport", delay = 0.5) +) +withr::defer(app$stop()) + +key_press <- key_press_factory(app) + +test_that("initial state, no cards are expanded", { + expect_no_full_screen(app) +}) + +# First card, no inputs -------------------------------------------- +test_that("fullscreen card without internal focusable elements", { + app_reset_no_full_screen(app) + + app_card_full_screen_enter(app, "card-no-inputs") + if (DO_SCREENSHOT) app$expect_screenshot() + + # Tabbing moves to exit button + key_press("Tab") + expect_focus(app, ".bslib-full-screen-exit") + + # Tabbing again stays on the exit button + key_press("Tab") + expect_focus(app, ".bslib-full-screen-exit") + + # Tabbing with shift stays on the exit button + key_press("Tab", shift = TRUE) + expect_focus(app, ".bslib-full-screen-exit") + + # Exit full screen + key_press("Enter") + expect_no_full_screen(app) +}) + +# Test enter/exit methods ------------------------------------------ +test_that("fullscreen card all exit methods", { + app_reset_no_full_screen(app) + + app_card_full_screen_enter(app, "card-no-inputs") + app_card_full_screen_exit(app, "click overlay") + + app_card_full_screen_enter(app, "card-no-inputs") + app_card_full_screen_exit(app, "click button") + + app_card_full_screen_enter(app, "card-no-inputs") + app_card_full_screen_exit(app, "escape") + + app_card_full_screen_enter(app, "card-no-inputs") + app_card_full_screen_exit(app, "space button") + + app_card_full_screen_enter(app, "card-no-inputs") + app_card_full_screen_exit(app, "enter button") +}) + +# Second card with inputs ------------------------------------------ +test_that("fullscreen card with inputs and interior cards", { + app_reset_no_full_screen(app) + + app_card_full_screen_enter(app, "card-with-inputs") + if (DO_SCREENSHOT) app$expect_screenshot() + + # Tabbing moves to first input + key_press("Tab") + expect_focus(app, "#letter-selectized") + + # Tabbing backwards moves to exit button + key_press("Tab", shift = TRUE) + expect_focus(app, ".bslib-full-screen-exit") + + # Tabbing backwards moves to last input + key_press("Tab", shift = TRUE) + expect_focus(app, "#go") + + # Tabbing forwards returns to exit button + key_press("Tab") + expect_focus(app, ".bslib-full-screen-exit") + + # If focus moves outside of card (somehow), tabbing returns focus to card + app$run_js("document.getElementById('neutral-focus-zone').focus()") + expect_focus(app, "#neutral-focus-zone") + key_press("Tab") + expect_focus(app, "#card-with-inputs") + + # Internal expand icons are hidden + expect_display(app, "none", "#card-with-inputs-left .bslib-full-screen-enter") + expect_display(app, "none", "#card-with-inputs-right .bslib-full-screen-enter") + + # Exit full screen + app_card_full_screen_exit(app, "escape") +}) + +# Interior card with inputs left (Tab forwards) -------------------- +test_that("fullscreen interior card with inputs (forward tab cycle)", { + app_reset_no_full_screen(app) + + app_card_full_screen_enter(app, "card-with-inputs-left") + if (DO_SCREENSHOT) app$expect_screenshot() + + # Tab through inputs + key_press("Tab") + expect_focus(app, "#letter-selectized") + key_press("Tab") + expect_focus(app, "#letter2-selectized") + key_press("Tab") + expect_focus(app, "#dates input:first-child") + key_press("Tab") + expect_focus(app, "#dates input:last-child") + key_press("Tab") + expect_focus(app, ".bslib-full-screen-exit") + key_press("Tab") + expect_focus(app, "#letter-selectized") + + # Go back to date input to ensure popup is closed + # FIXME: We should fix this in {bslib} (tab handlers too aggressive) + key_press("Tab") + key_press("Tab") + key_press("Tab") + key_press("Escape") + expect_focus(app, "#dates input:last-child") + expect_card_full_screen(app, "card-with-inputs-left") + + app_card_full_screen_exit(app, "click overlay") +}) + +# Escape while select box is open ----------------------------------- +test_that("escape while select box open exits select, not full screen", { + app_reset_no_full_screen(app) + + app_card_full_screen_enter(app, "card-with-inputs-left") + + # Tab to expand select box + key_press("Tab") + expect_focus(app, "#letter-selectized") + + # Escape doesn't leave full screen + key_press("Escape") + + if (app$get_js("document.activeElement.tagName === 'BODY'")) { + # In this browser, the select box is closed, but focus is lost + expect_true( + app$get_js('document.body.classList.contains("bslib-has-full-screen")') + ) + key_press("Tab") + expect_card_full_screen(app, "card-with-inputs-left") + skip("Escape on selectize closes select box, but focus moves to body") + } + + expect_card_full_screen(app, "card-with-inputs-left") + + # Tab to expand next select box + key_press("Tab") + expect_focus(app, "#letter2-selectized") + # Escape doesn't leave full screen here either + key_press("Escape") + expect_card_full_screen(app, "card-with-inputs-left") + + app_card_full_screen_exit(app, "click overlay") +}) + +# Interior focus is retained ---------------------------------- +test_that("interior focus is retains when entering full screen", { + app_reset_no_full_screen(app) + + # focus on an interior element should be maintained. This happens because + # we are triggering the full screen programmatically, in practice focus moves + # when users click. This test is still valuable for future server-side methods + app$run_js("document.getElementById('word').focus()") + expect_focus(app, "#word") + + app_card_full_screen_enter(app, "card-with-inputs-right") + expect_focus(app, "#word") + + app_card_full_screen_exit(app) + expect_focus(app, "#word") +}) + +# Interior card with inputs right (Tab backwards) -------------- +test_that("fullscreen interior card with inputs (backward tab cycle)", { + app_reset_no_full_screen(app) + + app$run_js("document.body.focus()") + app_card_full_screen_enter(app, "card-with-inputs-right") + expect_focus(app, "#card-with-inputs-right") + if (DO_SCREENSHOT) app$expect_screenshot() + + key_press("Tab") + key_press("Tab") + expect_focus(app, "#word") + + key_press("Tab", shift = TRUE) + expect_true(app$get_js( # sliders are weird inputs + "document.getElementById('slider-label').nextElementSibling.contains(document.activeElement)" + )) + + key_press("Tab", shift = TRUE) + expect_focus(app, ".bslib-full-screen-exit") + + key_press("Tab", shift = TRUE) + expect_focus(app, "#sentence") + + key_press("Tab", shift = TRUE) + expect_focus(app, "#word") + + app_card_full_screen_exit(app, "click button") + expect_focus(app, "#word") +}) + +# Final card ------------------------------------------------------ +test_that("fullscreen card with large plotly plot", { + app_reset_no_full_screen(app) + + app$run_js("document.getElementById('card-with-plot').scrollIntoView(true)") + + app_card_full_screen_enter(app, "card-with-plot") + # no screenshot here, it's too volatile + + key_press("Tab") + expect_focus(app, "#search") + + key_press("Tab") + expect_true(app$get_js( # moves into plotly plot + "document.querySelector('.plotly').contains(document.activeElement)" + )) + + key_press("Tab", shift = TRUE) + key_press("Tab", shift = TRUE) + expect_focus(app, ".bslib-full-screen-exit") + app_card_full_screen_exit(app, "enter button") +}) diff --git a/inst/apps/sysinfo-linux-3.6.txt b/inst/apps/sysinfo-linux-3.6.txt index 9c823b5814..f4db34c34c 100644 --- a/inst/apps/sysinfo-linux-3.6.txt +++ b/inst/apps/sysinfo-linux-3.6.txt @@ -184,7 +184,6 @@ renv 0.17.3 2023-04-06 [1] RSPM repr 1.1.6 2023-01-26 [1] RSPM reshape 0.8.9 2022-04-12 [1] RSPM - reshape2 1.4.4 2020-04-09 [1] RSPM reticulate 1.28 2023-01-27 [1] RSPM rex 1.2.1 2021-11-26 [1] RSPM rgeos 0.6-2 2023-03-02 [1] RSPM diff --git a/inst/apps/sysinfo-linux-4.0.txt b/inst/apps/sysinfo-linux-4.0.txt index 887015f634..e8db9b681f 100644 --- a/inst/apps/sysinfo-linux-4.0.txt +++ b/inst/apps/sysinfo-linux-4.0.txt @@ -186,7 +186,6 @@ renv 0.17.3 2023-04-06 [1] RSPM repr 1.1.6 2023-01-26 [1] RSPM reshape 0.8.9 2022-04-12 [1] RSPM - reshape2 1.4.4 2020-04-09 [1] RSPM reticulate 1.28 2023-01-27 [1] RSPM rex 1.2.1 2021-11-26 [1] RSPM rgeos 0.6-2 2023-03-02 [1] RSPM diff --git a/inst/apps/sysinfo-linux-4.1.txt b/inst/apps/sysinfo-linux-4.1.txt index eb3b7aacf2..ea4064b267 100644 --- a/inst/apps/sysinfo-linux-4.1.txt +++ b/inst/apps/sysinfo-linux-4.1.txt @@ -186,7 +186,6 @@ renv 0.17.3 2023-04-06 [1] RSPM repr 1.1.6 2023-01-26 [1] RSPM reshape 0.8.9 2022-04-12 [1] RSPM - reshape2 1.4.4 2020-04-09 [1] RSPM reticulate 1.28 2023-01-27 [1] RSPM rex 1.2.1 2021-11-26 [1] RSPM rgeos 0.6-2 2023-03-02 [1] RSPM diff --git a/inst/apps/sysinfo-linux-4.2.txt b/inst/apps/sysinfo-linux-4.2.txt index 3d2cb7f02d..e6f8b9f9a2 100644 --- a/inst/apps/sysinfo-linux-4.2.txt +++ b/inst/apps/sysinfo-linux-4.2.txt @@ -187,7 +187,6 @@ renv 0.17.3 2023-04-06 [1] RSPM repr 1.1.6 2023-01-26 [1] RSPM reshape 0.8.9 2022-04-12 [1] RSPM - reshape2 1.4.4 2020-04-09 [1] RSPM reticulate 1.28 2023-01-27 [1] RSPM rex 1.2.1 2021-11-26 [1] RSPM rgeos 0.6-2 2023-03-02 [1] RSPM diff --git a/inst/apps/sysinfo-linux-4.3.txt b/inst/apps/sysinfo-linux-4.3.txt index 1446246f90..3472bae670 100644 --- a/inst/apps/sysinfo-linux-4.3.txt +++ b/inst/apps/sysinfo-linux-4.3.txt @@ -186,7 +186,6 @@ renv 0.17.3 2023-04-06 [1] RSPM repr 1.1.6 2023-01-26 [1] RSPM reshape 0.8.9 2022-04-12 [1] RSPM - reshape2 1.4.4 2020-04-09 [1] RSPM reticulate 1.28 2023-01-27 [1] RSPM rex 1.2.1 2021-11-26 [1] RSPM rgeos 0.6-2 2023-03-02 [1] RSPM diff --git a/inst/apps/sysinfo-mac-4.0.txt b/inst/apps/sysinfo-mac-4.0.txt index 3498046300..3a4b36eea4 100644 --- a/inst/apps/sysinfo-mac-4.0.txt +++ b/inst/apps/sysinfo-mac-4.0.txt @@ -184,7 +184,6 @@ renv 0.15.4 2022-03-03 [1] CRAN (R 4.0.5) repr 1.1.4 2022-01-04 [1] CRAN (R 4.0.5) reshape 0.8.8 2018-10-23 [1] CRAN (R 4.0.2) - reshape2 1.4.4 2020-04-09 [1] CRAN (R 4.0.2) reticulate 1.24 2022-01-26 [1] CRAN (R 4.0.5) rex 1.2.1 2021-11-26 [1] CRAN (R 4.0.2) rgeos 0.5-9 2021-12-15 [1] CRAN (R 4.0.2) diff --git a/inst/apps/sysinfo-mac-4.2.txt b/inst/apps/sysinfo-mac-4.2.txt index dd3a20aaad..4f0367bc14 100644 --- a/inst/apps/sysinfo-mac-4.2.txt +++ b/inst/apps/sysinfo-mac-4.2.txt @@ -186,7 +186,6 @@ renv 0.17.3 2023-04-06 [1] CRAN (R 4.2.0) repr 1.1.6 2023-01-26 [1] CRAN (R 4.2.0) reshape 0.8.9 2022-04-12 [1] CRAN (R 4.2.0) - reshape2 1.4.4 2020-04-09 [1] CRAN (R 4.2.0) reticulate 1.28 2023-01-27 [1] CRAN (R 4.2.0) rex 1.2.1 2021-11-26 [1] CRAN (R 4.2.0) rgeos 0.6-2 2023-03-02 [1] CRAN (R 4.2.0) diff --git a/inst/helpers/keyboard.R b/inst/helpers/keyboard.R new file mode 100644 index 0000000000..0faacfe978 --- /dev/null +++ b/inst/helpers/keyboard.R @@ -0,0 +1,64 @@ +key_press_factory <- function(app) { + brwsr <- app$get_chromote_session() + + function( + which = "Tab", + shift = FALSE, + command = FALSE, + control = FALSE, + alt = FALSE + ) { + virtual_code <- switch( + which, + Tab = 9, + Enter = 13, + Escape = 27, + ArrowLeft = 37, + ArrowUp = 38, + ArrowRight = 39, + ArrowDown = 40, + Backspace = 8, + Delete = 46, + Home = 36, + End = 35, + PageUp = 33, + PageDown = 34, + Space = 32 + ) + + key <- switch( + which, + Space = " ", + which + ) + + modifiers <- 0 + if (shift) modifiers <- modifiers + 8 + if (command) modifiers <- modifiers + 4 + if (control) modifiers <- modifiers + 2 + if (alt) modifiers <- modifiers + 1 + + events <- + brwsr$Input$dispatchKeyEvent( + "rawKeyDown", + windowsVirtualKeyCode = virtual_code, + code = which, + key = key, + modifiers = modifiers, + wait_ = FALSE + )$then(function(value) { + brwsr$Input$dispatchKeyEvent( + "keyUp", + windowsVirtualKeyCode = virtual_code, + code = which, + key = key, + modifiers = modifiers, + wait_ = FALSE + ) + }) + + brwsr$wait_for(events) + + invisible(app) + } +}