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

add wrapper function for reactable #87

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ Imports:
shinyGovstyle,
shinyjs,
stringr,
styler
styler,
reactable
Suggests:
devtools,
diffviewer,
Expand Down
75 changes: 75 additions & 0 deletions R/dfe_reactable.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#' Department for Education Reactable Wrapper
#'
#' A wrapper around the `reactable` function for creating styled, accessible,
#' and user-friendly tables tailored to the Department for Education's
#' requirements.
#'
#' @param data A data frame to display in the table.
#' @param ... Additional arguments passed to `reactable::reactable`.
#'
#' @details
#' The `dfe_reactable` function provides a pre-configured version of
#' the `reactable` function with:
#' \itemize{
#' \item **Highlighting**: Row highlighting enabled.
#' \item **Borderless Table**: Removes borders for a clean look.
#' \item **Sort Icons Hidden**: Sort icons are not displayed by default.
#' \item **Resizable Columns**: Users can resize columns.
#' \item **Full Width**: Table expands to the full width of the container.
#' \item **Default Column Definition**: Custom column header styles,
#' NA value handling,
#' and alignment.
#' \item **Custom Search Input**: A search bar styled to the Department
#' for Education's specifications.
#' \item **Custom Language**: Provides a user-friendly search placeholder
#' text.
#' }
#'
#' @return A `reactable` HTML widget object.
#'
#' @examples
#' if (interactive()) {
#' library(shiny)
#' library(dfeshiny)
#' ui <- fluidPage(
#' h1("Example of dfe_reactable in a Shiny app"),
#' dfe_reactable(mtcars)
#' )
#' server <- function(input, output, session) {}
#' shinyApp(ui, server)
#' }
dfe_reactable <- function(data, ...) {
reactable::reactable(
data,
highlight = TRUE,
oadetayo marked this conversation as resolved.
Show resolved Hide resolved
borderless = TRUE,
showSortIcon = TRUE,
resizable = TRUE,
fullWidth = TRUE,
defaultColDef = reactable::colDef(
headerClass = "govuk-table__header",
html = TRUE,
na = "NA",
minWidth = 65,
align = "left",
class = "govuk-table__cell"
),
oadetayo marked this conversation as resolved.
Show resolved Hide resolved
rowClass = "govuk-table__row",
language = reactable::reactableLang(
oadetayo marked this conversation as resolved.
Show resolved Hide resolved
searchPlaceholder = "Search table..."
),
theme = reactable::reactableTheme(
searchInputStyle = list(
float = "right",
width = "25%",
marginBottom = "10px",
padding = "5px",
fontSize = "14px",
border = "1px solid #ccc",
borderRadius = "5px"
)
),
class = "gov-table",
...
)
oadetayo marked this conversation as resolved.
Show resolved Hide resolved
}
4 changes: 4 additions & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ reference:
desc: A wrapper for shinyGovstyle::header() that automatically uses the DfE logo.
contents:
- header
- title: Charts and Tables
desc: Functions to create and manage tables and visualisations.
contents:
- dfe_reactable
51 changes: 51 additions & 0 deletions inst/www/css/reactable_wrapper.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.govuk-table {
font-family: GDS Transport, arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 400;
font-size: 1rem;
line-height: 1.25;
color: #0b0c0c;
width: 100%;
margin-bottom: 20px;
border-spacing: 0;
border-collapse: collapse
}

@media print {
.govuk-table {
font-family: sans-serif
}
}

@media (min-width:40.0625em) {
.govuk-table {
font-size: 1.1875rem;
line-height: 1.3157894737
}
}

@media print {
.govuk-table {
font-size: 14pt;
line-height: 1.15;
color: #000
}
}

@media (min-width:40.0625em) {
.govuk-table {
margin-bottom: 30px
}
}

.govuk-table__header {
font-weight: 700
}

.govuk-table__cell, .govuk-table__header {
padding: 10px 20px 10px 0;
border-bottom: 1px solid #b1b4b6;
text-align: left;
vertical-align: top
}
51 changes: 51 additions & 0 deletions man/dfe_reactable.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tests/test_dashboard/server.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@
input_cookies = shiny::reactive(input$cookies),
google_analytics_key = ga_key # nolint: [object_usage_linter]
)

output$reactable_example <- reactable::renderReactable(
dfe_reactable(mtcars |> dplyr::select("mpg", "cyl", "hp", "gear"))

Check notice

Code scanning / lintr

Indentation should be 4 spaces but is 5 spaces. Note test

Indentation should be 4 spaces but is 5 spaces.
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"output": {

}
}
13 changes: 13 additions & 0 deletions tests/test_dashboard/tests/testthat/test-UI-04-table.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
app <- AppDriver$new(
name = "table_example",
expect_values_screenshot_args = FALSE
)

app$wait_for_idle(50)

test_that("Table renders as expected", {
# Check the initial rendering of the table
app$wait_for_idle(50)
app$expect_values(output = "reactable_example")
})

Dismissed Show dismissed Hide dismissed
8 changes: 8 additions & 0 deletions tests/test_dashboard/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ ui <- function(input, output, session) {
),
" code in a cave without distractions."
)
),

## Example table panel --------------------------------------------------------
shiny::tabPanel(
value = "table_panel_ui",
"Table example",
shiny::tags$h1("Reactable example"),
reactable::reactableOutput("reactable_example")
)
)
)
Expand Down
57 changes: 57 additions & 0 deletions tests/testthat/test-dfe_reactable.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
test_that("dfe_reactable produces a properly configured reactable object", {
# Generate a small sample dataset
sample_data <- data.frame(
Name = c("Alice", "Bob", "Charlie"),
Age = c(25, 30, 35),
Score = c(85.5, 90.3, 88.7)
)

# Run the function
table_output <- dfe_reactable(sample_data)

# Test if the output is a reactable object
expect_s3_class(table_output, "reactable")
expect_s3_class(table_output, "htmlwidget")

# Check the main attributes
expect_type(table_output$x, "list")
expect_true("tag" %in% names(table_output$x))

# Check the tag attribs
attribs <- table_output$x$tag$attribs
expect_type(attribs, "list")

# Verify key preconfigured attributes
expect_equal(attribs$resizable, TRUE)
expect_equal(attribs$highlight, TRUE)
expect_equal(attribs$borderless, TRUE)
expect_equal(attribs$showSortIcon, FALSE)

# Verify column definitions
columns <- attribs$columns
expect_equal(length(columns), 3) # Ensure 3 columns are defined

# Validate the first column's attributes
col1 <- columns[[1]]
expect_equal(col1$id, "Name")
expect_equal(col1$name, "Name")
expect_equal(col1$type, "character")
expect_equal(col1$html, TRUE)
expect_equal(col1$headerClassName, "govuk-table__header")

# Validate language configuration
language <- attribs$language
expect_type(language, "list")
expect_equal(language$searchPlaceholder, "Search table...")

# Validate theme configuration
theme <- attribs$theme
expect_type(theme, "list")
expect_equal(theme$searchInputStyle$float, "right")
expect_equal(theme$searchInputStyle$width, "25%")
expect_equal(theme$searchInputStyle$border, "1px solid #ccc")

# Validate the widget's overall class and package
expect_equal(attr(table_output, "class"), c("reactable", "htmlwidget"))
expect_equal(attr(table_output, "package"), "reactable")
})
Loading