Skip to content

Commit

Permalink
Modify icon() function to call fontawesome::fa_i() for equivalent…
Browse files Browse the repository at this point in the history
… functionality (#3302)

* Use `fontawesome::fa_i()` for FA <i> tags

* Remove fontawesome vendor files

* Add fontawesome pkg to Imports & Remotes

* Remove FontAwesome `person()` entry

* Remove Font Awesome license info

* Delete font-awesome.R

* Update 'Collate' field (removes 'font-awesome.R')

* Delete updateFontAwesome.R

* Prefer use of `fontawesome::fa()`

* Improve function documentation

* Update help file using roxygen

* Modify icon name

* Update icon name in example

* Modify icon name in example

* Update help files

* Update bootstrap.R

* Update icon.Rd

* Update bootstrap.R

* Revert `showcaseCodeTabs()` to use FA v4 name

* Revert icon name in example (back to FA v4)

* Remove `call. = FALSE` in `stop()`

* Remove `fontawesome` from Remotes

* Add min version req for the fontawesome pkg

* Increase minimum version requirement for fontawesome

* Update roxygen docs for `icon()`

* Document (GitHub Actions)

* Update icon.Rd

* Generate early return <i> tag for tabsetPanel logic

* Close #3384 and #3383: simplify and correct icon() logic

* Install htmltools PR for now

* Document (GitHub Actions)

* Avoid using tag attribs to hold non-attribute values

* Better legacy support

* No need to call prepTabIcon() twice

* code review

* Fix glyphicon class creation

* update news

Co-authored-by: Carson Sievert <[email protected]>
Co-authored-by: rich-iannone <[email protected]>
Co-authored-by: cpsievert <[email protected]>
  • Loading branch information
4 people authored May 12, 2021
1 parent 383fa6c commit d65ad5e
Show file tree
Hide file tree
Showing 27 changed files with 102 additions and 17,539 deletions.
4 changes: 1 addition & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ Authors@R: c(
comment = "Bootstrap-datepicker library"),
person("Andrew", "Rowls", role = c("ctb", "cph"),
comment = "Bootstrap-datepicker library"),
person("Dave", "Gandy", role = c("ctb", "cph"),
comment = "Font-Awesome font"),
person("Brian", "Reavis", role = c("ctb", "cph"),
comment = "selectize.js library"),
person("Salmen", "Bejaoui", role = c("ctb", "cph"),
Expand Down Expand Up @@ -80,6 +78,7 @@ Imports:
mime (>= 0.3),
jsonlite (>= 0.9.16),
xtable,
fontawesome (>= 0.2.1),
htmltools (>= 0.5.1.9003),
R6 (>= 2.0),
sourcetools,
Expand Down Expand Up @@ -138,7 +137,6 @@ Collate:
'devmode.R'
'diagnose.R'
'fileupload.R'
'font-awesome.R'
'graph.R'
'reactives.R'
'reactive-domains.R'
Expand Down
444 changes: 0 additions & 444 deletions LICENSE

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ shiny 1.6.0.9000
* Closed #3321: New informative warning when `shiny.tag` object(s) are supplied to `...`. In this case we will continue to create an "empty" nav item and include the content on every tab, but the warning will mention the (new) `header`/`footer` args, which is likely what the user wants.
* Closed #3320: The HTML markup that `tabPanel()` et. al generate (for Bootstrap nav) is now Bootstrap 4+ compliant when used with `theme = bslib::bs_theme()`.
* Closed #1928: `NULL` values are now dropped instead of producing an empty nav item.

* `icon(lib="fontawesome")` is now powered by the `{fontawesome}` package, which will make it easier to use the latest FA icons in the future (by updating the `{fontawesome}` package). (#3302)

### Other improvements

Expand Down
141 changes: 66 additions & 75 deletions R/bootstrap.R
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,14 @@ navbarPage <- function(title,
#' @rdname navbarPage
#' @export
navbarMenu <- function(title, ..., menuName = title, icon = NULL) {
icon <- prepTabIcon(icon)
structure(list(title = title,
menuName = menuName,
tabs = list2(...),
iconClass = iconClass(icon)),
# Here for legacy reasons
# https://github.com/cran/miniUI/blob/74c87d3/R/layout.R#L369
iconClass = tagGetAttribute(icon, "class"),
icon = icon),
class = "shiny.navbarmenu")
}

Expand Down Expand Up @@ -641,13 +645,18 @@ helpText <- function(...) {
#' @export
#' @describeIn tabPanel Create a tab panel that can be included within a [tabsetPanel()] or a [navbarPage()].
tabPanel <- function(title, ..., value = title, icon = NULL) {
div(
icon <- prepTabIcon(icon)
pane <- div(
class = "tab-pane",
title = title,
`data-value` = value,
`data-icon-class` = iconClass(icon),
# Here for legacy reasons
# https://github.com/cran/miniUI/blob/74c87d/R/layout.R#L395
`data-icon-class` = tagGetAttribute(icon, "class"),
...
)
attr(pane, "_shiny_icon") <- icon
pane
}

isTabPanel <- function(x) {
Expand Down Expand Up @@ -879,17 +888,23 @@ findAndMarkSelectedTab <- function(tabs, selected, foundSelected) {
return(list(tabs = tabs, foundSelected = foundSelected))
}

# Returns the icon object (or NULL if none), provided either a
# tabPanel, OR the icon class
getIcon <- function(tab = NULL, iconClass = NULL) {
if (!is.null(tab)) iconClass <- tab$attribs$`data-icon-class`
if (!is.null(iconClass)) {
if (grepl("fa-", iconClass, fixed = TRUE)) {
# for font-awesome we specify fixed-width
iconClass <- paste(iconClass, "fa-fw")
}
icon(name = NULL, class = iconClass)
} else NULL
prepTabIcon <- function(x = NULL) {
if (is.null(x)) return(NULL)
if (!inherits(x, "shiny.tag")) {
stop(
"`icon` must be a `shiny.tag` object. ",
"Try passing `icon()` (or `tags$i()`) to the `icon` parameter.",
call. = FALSE
)
}

is_fa <- grepl("fa-", tagGetAttribute(x, "class") %||% "", fixed = TRUE)
if (!is_fa) {
return(x)
}

# for font-awesome we specify fixed-width
tagAppendAttributes(x, class = "fa-fw")
}

# Text filter for navbarMenu's (plain text) separators
Expand Down Expand Up @@ -990,15 +1005,14 @@ buildNavItem <- function(divTag, tabsetId, index) {
# https://github.com/rstudio/shiny/issues/3352
title <- divTag$attribs[["title"]]
value <- divTag$attribs[["data-value"]]
icon <- getIcon(iconClass = divTag$attribs[["data-icon-class"]])
active <- isTabSelected(divTag)
divTag <- tagAppendAttributes(divTag, class = if (active) "active")
divTag$attribs$id <- id
divTag$attribs$title <- NULL
list(
divTag = divTag,
liTag = tagAddRenderHook(
liTag(id, title, value, icon),
liTag(id, title, value, attr(divTag, "_shiny_icon")),
function(x) {
if (isTRUE(getCurrentThemeVersion() >= 4)) {
tagQuery(x)$
Expand Down Expand Up @@ -1053,7 +1067,7 @@ buildDropdown <- function(divTag, tabset) {
class = "dropdown-toggle",
`data-toggle` = "dropdown",
`data-value` = divTag$menuName,
getIcon(iconClass = divTag$iconClass),
divTag$icon,
divTag$title,
tags$b(class = "caret")
),
Expand Down Expand Up @@ -1565,32 +1579,31 @@ downloadLink <- function(outputId, label="Download", class=NULL, ...) {
#' Create an icon
#'
#' Create an icon for use within a page. Icons can appear on their own, inside
#' of a button, or as an icon for a [tabPanel()] within a
#' [navbarPage()].
#'
#' @param name Name of icon. Icons are drawn from the
#' [Font Awesome Free](https://fontawesome.com/) (currently icons from
#' the v5.13.0 set are supported with the v4 naming convention) and
#' [Glyphicons](https://getbootstrap.com/components/#glyphicons)
#' libraries. Note that the "fa-" and "glyphicon-" prefixes should not be used
#' in icon names (i.e. the "fa-calendar" icon should be referred to as
#' "calendar")
#' @param class Additional classes to customize the style of the icon (see the
#' of a button, and/or used with [tabPanel()] and [navbarMenu()].
#'
#' @param name The name of the icon. A name from either [Font
#' Awesome](https://fontawesome.com/) (when `lib="font-awesome"`) or
#' [Bootstrap
#' Glyphicons](https://getbootstrap.com/docs/3.3/components/#glyphicons) (when
#' `lib="glyphicon"`) may be provided. Note that the `"fa-"` and
#' `"glyphicon-"` prefixes should not appear in name (i.e., the
#' `"fa-calendar"` icon should be referred to as `"calendar"`). A `name` of
#' `NULL` may also be provided to get a raw `<i>` tag with no library attached
#' to it.
#' @param class Additional classes to customize the style of an icon (see the
#' [usage examples](https://fontawesome.com/how-to-use) for details on
#' supported styles).
#' @param lib Icon library to use ("font-awesome" or "glyphicon")
#' @param ... Arguments passed to the `<i>` tag of [htmltools::tags]
#' @param lib The icon library to use. Either `"font-awesome"` or `"glyphicon"`.
#' @param ... Arguments passed to the `<i>` tag of [htmltools::tags].
#'
#' @return An icon element
#'
#' @seealso For lists of available icons, see
#' [https://fontawesome.com/icons](https://fontawesome.com/icons) and
#' [https://getbootstrap.com/components/#glyphicons](https://getbootstrap.com/components/#glyphicons).
#' @return An `<i>` (icon) HTML tag.
#'
#' @seealso For lists of available icons, see <https://fontawesome.com/icons>
#' and <https://getbootstrap.com/docs/3.3/components/#glyphicons>
#'
#' @examples
#' # add an icon to a submit button
#' submitButton("Update View", icon = icon("refresh"))
#' submitButton("Update View", icon = icon("redo"))
#'
#' navbarPage("App Title",
#' tabPanel("Plot", icon = icon("bar-chart-o")),
Expand All @@ -1599,48 +1612,26 @@ downloadLink <- function(outputId, label="Download", class=NULL, ...) {
#' )
#' @export
icon <- function(name, class = NULL, lib = "font-awesome", ...) {
prefixes <- list(
"font-awesome" = "fa",
"glyphicon" = "glyphicon"
)
prefix <- prefixes[[lib]]

# determine stylesheet
if (is.null(prefix)) {
stop("Unknown font library '", lib, "' specified. Must be one of ",
paste0('"', names(prefixes), '"', collapse = ", "))
# A NULL name allows for a generic <i> not tied to any library
if (is.null(name)) {
lib <- "none"
}

# build the icon class (allow name to be null so that other functions
# e.g. buildTabset can pass an explicit class value)
iconClass <- ""
if (!is.null(name)) {
prefix_class <- prefix
if (prefix_class == "fa" && name %in% font_awesome_brands) {
prefix_class <- "fab"
}
iconClass <- paste0(prefix_class, " ", prefix, "-", name)
}
if (!is.null(class))
iconClass <- paste(iconClass, class)

iconTag <- tags$i(class = iconClass, role = "presentation", `aria-label` = paste(name, "icon"), ...)

# font-awesome needs an additional dependency (glyphicon is in bootstrap)
if (lib == "font-awesome") {
htmlDependencies(iconTag) <- htmlDependency(
"font-awesome", "5.13.0", "www/shared/fontawesome", package = "shiny",
stylesheet = c(
"css/all.min.css",
"css/v4-shims.min.css"
)
)
}

htmltools::browsable(iconTag)
switch(
lib %||% "",
"none" = iconTag(name, class = class, ...),
"font-awesome" = fontawesome::fa_i(name = name, class = class, ...),
"glyphicon" = iconTag(
name, class = "glyphicon", class = paste0("glyphicon-", name),
class = class, ...
),
stop("Unknown icon library: ", lib, ". See `?icon` for supported libraries.")
)
}

# Helper funtion to extract the class from an icon
iconClass <- function(icon) {
if (!is.null(icon)) icon$attribs$class
iconTag <- function(name, ...) {
htmltools::browsable(
tags$i(..., role = "presentation", `aria-label` = paste(name, "icon"))
)
}
Loading

0 comments on commit d65ad5e

Please sign in to comment.