|
16 | 16 | #' @param rules Any [sass::as_sass()] `input` to place after Bootstrap's SASS imports. |
17 | 17 | #' @param ... For `bs_theme_add_variables()`, these arguments define SASS variables; |
18 | 18 | #' otherwise, these arguments are passed along to [sass::sass_layer()]. |
| 19 | +#' @param .where whether to place the variable definitions before other |
| 20 | +#' Sass `"defaults"`, after other Sass `"declarations"`, or after other Sass `"rules"`. |
| 21 | +#' @param .default_flag whether or not to add a `!default` flag (if missing) to |
| 22 | +#' variable expressions. It's recommended to keep this as `TRUE` when |
| 23 | +#' `.where = "defaults"`. |
19 | 24 | #' |
20 | 25 | #' @references \url{https://getbootstrap.com/docs/4.4/getting-started/theming/} |
21 | 26 | #' |
@@ -57,23 +62,55 @@ bs_theme_new <- function(version = version_default(), bootswatch = NULL) { |
57 | 62 |
|
58 | 63 | #' @rdname theming |
59 | 64 | #' @export |
60 | | -bs_theme_add_variables <- function(...) { |
| 65 | +bs_theme_add_variables <- function(..., .where = "defaults", |
| 66 | + .default_flag = identical(.where, "defaults")) { |
61 | 67 | vars <- rlang::list2(...) |
62 | 68 | if (any(names2(vars) == "")) stop("Variables must be named.", call. = FALSE) |
63 | | - bs_theme_add(vars) |
| 69 | + .where <- match.arg(.where, c("defaults", "declarations", "rules")) |
| 70 | + |
| 71 | + # Workaround to the problem of 'blue' winning in the scenario of: |
| 72 | + # bs_theme_add_variables("body-bg" = "blue") |
| 73 | + # bs_theme_add_variables("body-bg" = "red") |
| 74 | + if (.default_flag) { |
| 75 | + vars <- ensure_default_flag(vars) |
| 76 | + } |
| 77 | + |
| 78 | + do.call(bs_theme_add, setNames(list(vars), .where)) |
| 79 | +} |
| 80 | + |
| 81 | +# Given a named list of variable definitions, |
| 82 | +# searches each variable's expression for a !default flag, |
| 83 | +# and if missing, adds it. |
| 84 | +ensure_default_flag <- function(vars) { |
| 85 | + Map( |
| 86 | + function(key, val) { |
| 87 | + val <- paste(sass::as_sass(val), collapse = "\n") |
| 88 | + if (grepl("!default\\s*;*\\s*$", val)) { |
| 89 | + val |
| 90 | + } else { |
| 91 | + paste(sub(";+$", "", val), "!default") |
| 92 | + } |
| 93 | + }, names(vars), vars |
| 94 | + ) |
64 | 95 | } |
65 | 96 |
|
66 | 97 | #' @rdname theming |
67 | 98 | #' @export |
68 | | -bs_theme_add <- function(defaults = "", rules = "", ...) { |
| 99 | +bs_theme_add <- function(defaults = "", declarations = "", rules = "", ...) { |
69 | 100 | old_theme <- bs_theme_get() |
70 | 101 | if (is.null(old_theme)) { |
71 | 102 | stop("Must call bs_theme_new() before adding to the theme.", call. = FALSE) |
72 | 103 | } |
73 | | - layer <- if (inherits(defaults, "sass_layer")) { |
74 | | - defaults |
| 104 | + if (inherits(defaults, "sass_layer")) { |
| 105 | + if (!identical(declarations, "") || !identical(rules, "") || length(list(...)) > 0) { |
| 106 | + stop( |
| 107 | + "Not allowed to specify other arguments when the first argument, `defaults`, ", |
| 108 | + "is a sass_layer()", call. = FALSE |
| 109 | + ) |
| 110 | + } |
| 111 | + layer <- defaults |
75 | 112 | } else { |
76 | | - sass_layer(defaults = defaults, rules = rules, ...) |
| 113 | + layer <- sass_layer(defaults = defaults, declarations = declarations, rules = rules, ...) |
77 | 114 | } |
78 | 115 | layer <- sass_layer_merge(old_theme, layer) |
79 | 116 | bs_theme_set(add_class(layer, "bs_theme")) |
|
0 commit comments