├── .Rbuildignore ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── Keyframes.R ├── Selector.R ├── Style.R ├── StyleSheet.R ├── aaa.R ├── prop.R ├── prop_animation.R ├── prop_transform.R ├── utils-multi-args.R └── utils.R ├── README.Rmd ├── README.md ├── data-raw ├── CSSProperties.json └── property-info.R ├── deprecated └── css_dec_methods.R ├── man ├── Keyframe.Rd ├── Keyframes.Rd ├── Selector.Rd ├── Style.Rd ├── StyleSheet.Rd ├── all_named.Rd ├── as.character.Selector.Rd ├── as.character.Style.Rd ├── as.character.StyleSheet.Rd ├── as.character.css_property.Rd ├── css_prop.Rd ├── css_sel.Rd ├── css_style.Rd ├── figures │ ├── hello.gif │ ├── inline1.png │ ├── inline2.png │ ├── logo.png │ ├── mini-cooper-s.gif │ ├── readme.gif │ └── shiny.png ├── imp.Rd └── print.css_property.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico └── vignettes ├── .gitignore ├── Properties.Rmd ├── Selectors.Rmd ├── Shiny.Rmd ├── StyleSheets.Rmd ├── Styles.Rmd └── animation.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README\.Rmd$ 4 | ^working$ 5 | ^data-raw$ 6 | ^deprecated$ 7 | ^pkgdown$ 8 | ^\.travis\.yml$ 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .Rhistory 3 | *.Rproj 4 | .Rproj.user 5 | *.swp 6 | working 7 | *.txt 8 | inst/doc 9 | doc 10 | Meta 11 | crap.pdf 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: minicss 2 | Type: Package 3 | Title: CSS Builder 4 | Version: 0.1.0 5 | Author: mikefc 6 | Maintainer: mikefc 7 | Description: CSS builder. 8 | License: MIT + file LICENSE 9 | Encoding: UTF-8 10 | LazyData: true 11 | Imports: 12 | R6, 13 | glue 14 | RoxygenNote: 6.1.1 15 | Suggests: 16 | knitr, 17 | rmarkdown, 18 | htmltools 19 | VignetteBuilder: knitr 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 mikefc@coolbutuseless.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.character,Selector) 4 | S3method(as.character,Style) 5 | S3method(as.character,StyleSheet) 6 | S3method(as.character,css_property) 7 | S3method(print,css_property) 8 | export(Keyframe) 9 | export(Keyframes) 10 | export(Selector) 11 | export(Style) 12 | export(StyleSheet) 13 | export(css_keyframe) 14 | export(css_keyframes) 15 | export(css_prop) 16 | export(css_sel) 17 | export(css_style) 18 | export(css_stylesheet) 19 | export(imp) 20 | import(R6) 21 | import(glue) 22 | importFrom(stats,setNames) 23 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # minicss 0.1.0 2 | 3 | * Initial release 4 | -------------------------------------------------------------------------------- /R/Keyframes.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | #' Create a single keyframe for a style at a moment in time. 5 | #' 6 | #' This is identical to the \code{Style} class except the first argument is a 7 | #' time specification (either 'from', 'to', or a percentage), instead of a name 8 | #' 9 | #' 10 | #' @examples 11 | #' \dontrun{ 12 | #' Keyframe$new('from', color = '#000000') 13 | #' Keyframe$new('to' , color = '#ffffff') 14 | #' } 15 | #' 16 | #' @import R6 17 | #' @export 18 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | Keyframe <- R6::R6Class( 20 | "Keyframe", inherit = Style, 21 | 22 | public = list( 23 | initialize = function(time, ...) { 24 | if (!time %in% c('from', 'to') && !endsWith(time, '%')) { 25 | if (!(is.numeric(time) && time >= 0 && time <= 100)) { 26 | stop("Keyframe$new(): 'time' must be 'from', 'to' or a number between 0 and 100") 27 | } 28 | time <- paste0(time, '%') 29 | } 30 | 31 | super$initialize(selector = time, ..., indent = 1) 32 | } 33 | ) 34 | ) 35 | 36 | 37 | 38 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | #' Create a named Keyframes style suitable to insert in a StyleSheet 40 | #' 41 | #' @import R6 42 | #' @export 43 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | Keyframes <- R6::R6Class( 45 | "Keyframes", inherit = StyleSheet, 46 | 47 | public = list( 48 | name = NULL, 49 | 50 | initialize = function(name, ...) { 51 | if (!is.character(name)) { 52 | stop("Keyframes$new(): the first argument must be a character string representing a name, not: ", class(name)) 53 | } 54 | self$name <- name 55 | super$initialize(...) 56 | }, 57 | 58 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 59 | # Create a Style object, add it it to the current stylesheet and return it. 60 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 61 | add = function(time, ...) { 62 | this_keyframe <- Keyframe$new(time = time, ...) 63 | do.call(self$append, list(this_keyframe)) 64 | invisible(this_keyframe) 65 | }, 66 | 67 | as_character = function(...) { 68 | strings <- vapply(self$styles, function(x) {x$as_character()}, character(1)) 69 | children <- paste(strings, collapse = "\n") 70 | paste0("@keyframes ", self$name, " {\n", children, "\n}") 71 | } 72 | ) 73 | ) 74 | 75 | 76 | 77 | 78 | 79 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 80 | #' @usage NULL 81 | #' @rdname Keyframe 82 | #' @export 83 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 84 | css_keyframe <- function(time, ...) { 85 | Keyframe$new(time = time, ...) 86 | } 87 | 88 | 89 | 90 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 91 | #' @usage NULL 92 | #' @rdname Keyframes 93 | #' @export 94 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 95 | css_keyframes <- function(name, ...) { 96 | Keyframes$new(name = name, ...) 97 | } 98 | 99 | 100 | 101 | 102 | if (FALSE) { 103 | library(htmltools) 104 | library(minicss) 105 | 106 | # Construct individual frames 107 | k1 <- css_keyframe('from', color = '#ffffff') 108 | k2 <- css_keyframe('to' , color = '#123456', 109 | css_prop$transform$translateX(40)) 110 | 111 | # Combine frames into @keyframes 112 | kf <- css_keyframes('ex1', k1, k2) 113 | 114 | # Create style to attach @keyframes to the 'h1' type 115 | h1 <- css_style('h1', 116 | css_anim('ex1', duration = 1, direction = 'alternate') 117 | ) 118 | 119 | ## Create a style sheet 120 | ss <- css_stylesheet(h1, kf) 121 | 122 | # Create some html using this style sheet 123 | html <- glue::glue(" 124 | 125 | 126 | 127 |

Hello #RStats

128 | ") 129 | 130 | html_print(HTML(html)) 131 | } 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /R/Selector.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | # Collapse a name value pair into a string for a pseudo class or pseudo element 5 | # 6 | # either name:value for pseudo classes 7 | # or name::value for pseudo elements 8 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | collapse_pseudo <- function(name, value, prefix = ":") { 10 | if (isTRUE(value)) { 11 | paste0(prefix, name) 12 | } else { 13 | paste0(prefix, name, "(", value, ")") 14 | } 15 | } 16 | 17 | 18 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | #' CSS selector builder 20 | #' 21 | #' Based upon a naive reading of \url{https://developer.mozilla.org/en-US/docs/Web/CSS/Reference#Selectors}. 22 | #' 23 | #' @docType class 24 | #' 25 | #' @usage NULL 26 | #' @section Usage: 27 | #' \preformatted{selector <- Selector$new() 28 | #' selector <- css_sel() 29 | #' 30 | #' selector$type(type_name) 31 | #' selector$class(...) 32 | #' selector$id(id_name) 33 | #' 34 | #' new_selector <- selector$copy() 35 | #' 36 | #' } 37 | #' 38 | #' @format NULL 39 | #' 40 | #' @section Methods: 41 | #' 42 | #' \describe{ 43 | #' 44 | #' \item{\code{$type(type_name)}}{ 45 | #' Set the type for the selector 46 | #' \tabular{ll}{ 47 | #' \code{type_name} \tab type name \cr 48 | #' } 49 | #' } 50 | #' 51 | #' \item{\code{$id(id_name)}}{ 52 | #' Set the id for the selector 53 | #' \tabular{ll}{ 54 | #' \code{id_name} \tab id name \cr 55 | #' } 56 | #' } 57 | #' 58 | #' \item{\code{$class(...)}}{ 59 | #' Add to the class list for for the selector 60 | #' \tabular{ll}{ 61 | #' \code{...} \tab class names \cr 62 | #' } 63 | #' } 64 | #' 65 | #' \item{\code{$attr(..., modifier = c('exact', 'choice', 'prefix', 'suffix', 'contains'))}}{ 66 | #' Add attribute matching to the selector. See \url{https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors} 67 | #' \tabular{ll}{ 68 | #' \code{...} \tab name/value pairs for the atributes \cr 69 | #' \code{modifer} \tab by default 'exact' attribute matching, but can select from among the different types of matching \cr 70 | #' } 71 | #' } 72 | #' 73 | #' \item{\code{$pseudo_class(...)}}{ 74 | #' Set pseudo classes on the selector. 75 | #' \tabular{ll}{ 76 | #' \code{...} \tab Use \code{name = TRUE} to set pseudo-classes \cr 77 | #' } 78 | #' } 79 | #' 80 | #' \item{\code{$pseudo_element(...)}}{ 81 | #' Set pseudo element on the selector. 82 | #' \tabular{ll}{ 83 | #' \code{...} \tab Use \code{name = TRUE} to set pseudo-elements \cr 84 | #' } 85 | #' } 86 | #' 87 | #' 88 | #' 89 | #' \item{\code{$descendant_of(selector), $parent_of(selector), $child_of(selector), $prior_adjacent(selector), $prior_sibling(selector), $and(selector)}}{ 90 | #' Set relationship with another selector 91 | #' \tabular{ll}{ 92 | #' \code{selector} \tab Other selector \cr 93 | #' } 94 | #' } 95 | #' 96 | #' \item{\code{$as_character()}}{ 97 | #' Convert \code{Selector} to a character string. 98 | #' } 99 | #' 100 | #' \item{\code{$print()}}{ 101 | #' Print \code{Selector} to terminal. 102 | #' } 103 | #' 104 | #' \item{\code{$copy()}}{ 105 | #' Copy \code{Selector}. 106 | #' } 107 | #' 108 | #' } 109 | #' 110 | #' 111 | #' 112 | #' @examples 113 | #' \dontrun{ 114 | #' selector <- css_sel(".marsha")$child_of('carol') 115 | #' } 116 | #' 117 | #' @import R6 118 | #' @export 119 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 | Selector <- R6::R6Class( 121 | "Selector", 122 | 123 | 124 | public = list( 125 | 126 | .type = NULL, 127 | .id = NULL, 128 | .classes = NULL, 129 | .child = NULL, 130 | .parent = NULL, 131 | .sibling = NULL, 132 | .adjacent = NULL, 133 | .additional = NULL, 134 | .attr = NULL, 135 | .pseudo_class = NULL, 136 | .pseudo_element = NULL, 137 | 138 | initialize = function(selector = NULL) { 139 | self$.classes <- character(0) 140 | self$.sibling <- list() 141 | self$.additional <- list() 142 | self$.attr <- list() 143 | 144 | if (is.null(selector)) { 145 | # do nothing 146 | } else if (inherits(selector, 'Selector')) { 147 | for (name in names(Selector$public_fields)) { 148 | self[[name]] <- selector[[name]] 149 | } 150 | } else if (startsWith(selector, ".")) { 151 | self$class(selector) 152 | } else if (startsWith(selector, '#')) { 153 | self$id(selector) 154 | } else { 155 | self$type(selector) 156 | } 157 | 158 | invisible(self) 159 | }, 160 | 161 | 162 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 163 | # Type - singular 164 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 165 | type = function(type_name) { 166 | stopifnot(is.character(type_name)) 167 | self$.type <- type_name 168 | invisible(self) 169 | }, 170 | 171 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 172 | # classes - multiple 173 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 174 | class = function(...) { 175 | class_names <- as.character(list(...)) 176 | has_dot <- startsWith(class_names, ".") 177 | class_names[!has_dot] <- paste0(".", class_names[!has_dot]) 178 | 179 | if (any(substr(class_names, 2, 2) %in% 0:9)) { 180 | stop("Selector$class(): Class names cannot start with a digit") 181 | } 182 | 183 | self$.classes <- c(self$.classes, class_names) 184 | invisible(self) 185 | }, 186 | 187 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188 | # ID - singular 189 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 190 | id = function(id_name) { 191 | stopifnot(is.character(id_name)) 192 | if (!startsWith(id_name, "#")) { 193 | id_name <- paste0("#", id_name) 194 | } 195 | 196 | if (any(substr(id_name, 2, 2) %in% 0:9)) { 197 | stop("Selector$id(): ID name cannot start with a digit") 198 | } 199 | 200 | self$.id <- id_name 201 | invisible(self) 202 | }, 203 | 204 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 205 | # selector attributes 206 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 207 | attr = function(..., modifier = c('exact', 'choice', 'prefix', 'suffix', 'contains')) { 208 | named_value <- list(...) 209 | stopifnot(length(named_value) == 1) 210 | if (is.null(names(named_value))) { 211 | self$.attr <- c(self$.attr, named_value) 212 | } else { 213 | 214 | modifier <- match.arg(modifier) 215 | eq <- switch( 216 | modifier, 217 | exact = '=', 218 | choice = '~=', 219 | prefix = '^=', 220 | suffix = '$=', 221 | ) 222 | 223 | new_attr <- paste0(names(named_value), eq, '"', unname(named_value), '"') 224 | self$.attr <- c(self$.attr, new_attr) 225 | 226 | } 227 | invisible(self) 228 | }, 229 | 230 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 231 | # Pseudo class 232 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 233 | pseudo_class = function(active, any_link, blank, checked, default, defined, dir, disabled, empty, enabled, first, first_child, first_of_type, fullscreen, focus, focus_visible, focus_within, has, host, host_context, hover, indeterminate, in_range, invalid, is, lang, last_child, last_of_type, left, link, not, nth_child, nth_col, nth_last_child, nth_last_col, nth_last_of_type, nth_of_type, only_child, only_of_type, optional, out_of_range, read_only, read_write, required, right, root, scope, target, valid, visited, ...) { 234 | pcs <- find_args(...) 235 | 236 | pc_names <- names(pcs) 237 | pc_names <- gsub("_", "-", pc_names) 238 | 239 | pcs <- mapply(collapse_pseudo, pc_names, unname(pcs), MoreArgs = list(prefix = ':'), USE.NAMES = FALSE) 240 | 241 | self$.pseudo_class <- c(self$.pseudo_class, pcs) 242 | 243 | invisible(self) 244 | }, 245 | 246 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 247 | # Pseudo Element 248 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 249 | pseudo_element = function(after, before, cue, first_letter, first_line, selection, slotted, ...) { 250 | pes <- find_args(...) 251 | 252 | pe_names <- names(pes) 253 | pe_names <- gsub("_", "-", pe_names) 254 | 255 | 256 | pes <- mapply(collapse_pseudo, names(pes), unname(pes), MoreArgs = list(prefix = '::'), USE.NAMES = FALSE) 257 | 258 | self$.pseudo_element <- c(self$.pseudo_element, pes) 259 | 260 | invisible(self) 261 | }, 262 | 263 | 264 | 265 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 266 | # Combinators 267 | # descendant: A B 268 | # child: A > B 269 | # adjacent sibling; A + B 270 | # general sibling: A ~ B 271 | # 272 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 273 | descendant_of = function(selector) { 274 | self$.descendent <- selector 275 | invisible(self) 276 | }, 277 | 278 | parent_of = function(selector) { 279 | self$.child <- selector 280 | invisible(self) 281 | }, 282 | 283 | child_of = function(selector) { 284 | self$.parent <- selector 285 | invisible(self) 286 | }, 287 | 288 | prior_adjacent = function(selector) { 289 | self$.adjacent <- append(self$.adjacent, selector) 290 | invisible(self) 291 | }, 292 | 293 | prior_sibling = function(selector) { 294 | self$.sibling <- append(self$.sibling, selector, after = 0) 295 | self 296 | }, 297 | 298 | and = function(selector) { 299 | self$.additional <- append(self$.additional, selector) 300 | invisible(self) 301 | }, 302 | 303 | 304 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 305 | # Convert to character representation 306 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 307 | as_character = function(...) { 308 | id_text <- self$.id 309 | class_text <- paste(self$.classes, collapse="") 310 | 311 | if (!is.null(self$.child)) { 312 | child_text <- as.character(self$.child) 313 | child_text <- paste0(" > ", child_text) 314 | } else { 315 | child_text <- NULL 316 | } 317 | 318 | if (!is.null(self$.parent)) { 319 | parent_text <- as.character(self$.parent) 320 | parent_text <- paste0(parent_text, " > ") 321 | } else { 322 | parent_text <- NULL 323 | } 324 | 325 | if (length(self$.additional) > 0) { 326 | additional <- vapply(self$.additional, as.character, character(1)) 327 | additional <- paste0(additional, collapse = ", ") 328 | additional <- paste0(", ", additional) 329 | } else { 330 | additional <- NULL 331 | } 332 | 333 | if (length(self$.attr) > 0) { 334 | attr_text <- paste0('[', self$.attr, ']', sep = '', collapse = '') 335 | } else { 336 | attr_text <- NULL 337 | } 338 | 339 | if (length(self$.pseudo_class) > 0) { 340 | pseudo_class_text <- paste0(self$.pseudo_class, collapse = "") 341 | } else { 342 | pseudo_class_text <- NULL 343 | } 344 | 345 | if (length(self$.pseudo_element) > 0) { 346 | pseudo_element_text <- paste0(self$.pseudo_element, collapse = "") 347 | } else { 348 | pseudo_element_text <- NULL 349 | } 350 | 351 | 352 | paste0(parent_text, self$.type, id_text, class_text, pseudo_class_text, 353 | pseudo_element_text, attr_text, child_text, additional) 354 | }, 355 | 356 | 357 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 358 | # Print 359 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 360 | print = function(...) { 361 | cat(self$as_character(...)) 362 | }, 363 | 364 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 365 | # Selector objects don't contain any R6 objects, so fine to just do 366 | # a shallow ocpy 367 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 368 | copy = function(...) { 369 | self$clone(...) 370 | } 371 | 372 | ) 373 | ) 374 | 375 | 376 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 377 | #' Retrieve the character representation of a Selector object 378 | #' 379 | #' @param x Selector object 380 | #' @param ... other arguments 381 | #' 382 | #' @export 383 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 384 | as.character.Selector <- function(x, ...) { 385 | x$as_character(...) 386 | } 387 | 388 | 389 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 390 | #' Helper for creating a Selector object 391 | #' 392 | #' @param selector string or another Selector object to clone 393 | #' 394 | #' @export 395 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 396 | css_sel <- function(selector = NULL) { 397 | Selector$new(selector) 398 | } 399 | 400 | -------------------------------------------------------------------------------- /R/Style.R: -------------------------------------------------------------------------------- 1 | 2 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | #' CSS style builder 4 | #' 5 | #' @docType class 6 | #' 7 | #' @usage NULL 8 | #' @section Usage: 9 | #' \preformatted{style <- Style$new() 10 | #' style <- css_style() 11 | #' 12 | #' style$set_selector(".thing") 13 | #' style$remove("color") 14 | #' style$update(color = 'blue') 15 | #' style$as_character() 16 | #' style$as_inline() 17 | #' new_style <- style$copy() 18 | #' 19 | #' } 20 | #' 21 | #' @format NULL 22 | #' 23 | #' @section Methods: 24 | #' 25 | #' \describe{ 26 | #' 27 | #' \item{\code{$update(..., selector = NULL)}}{ 28 | #' Updates the list of properties associated with this style. 29 | #' \tabular{ll}{ 30 | #' \code{...} \tab name/value properties \cr 31 | #' \code{selector} \tab If given, then used as the the selector for this style. If 32 | #' not given, then the first unnamed argument in \code{...} is interpreted as the 33 | #' character string for the selector. \cr 34 | #' } 35 | #' } 36 | #' 37 | #' \item{\code{$set_selector(selector)}}{ 38 | #' Updates the selector associated with this style. 39 | #' \tabular{ll}{ 40 | #' \code{selector} \tab new selector. either a character string or a \code{Selector} object \cr 41 | #' } 42 | #' } 43 | #' 44 | #' \item{\code{$remove(...)}}{ 45 | #' Removes properties from this style by name 46 | #' \tabular{ll}{ 47 | #' \code{...} \tab names of properties to remove (character strings) \cr 48 | #' } 49 | #' } 50 | #' 51 | #' \item{\code{$as_character()}}{ 52 | #' Convert \code{Style} to a character string. 53 | #' } 54 | #' 55 | #' \item{\code{$as_inline()}}{ 56 | #' Convert \code{Style} to a single character string without the selector, 57 | #' suitable for use as an inline style. 58 | #' } 59 | #' 60 | #' \item{\code{$print()}}{ 61 | #' Print \code{Style} to terminal. 62 | #' } 63 | #' 64 | #' \item{\code{$copy()}}{ 65 | #' Copy \code{Style}. 66 | #' } 67 | #' 68 | #'} 69 | #' 70 | #' 71 | #' @examples 72 | #' \dontrun{ 73 | #' css_style('#marsha')$ 74 | #' update(marsha = 'marsha')$ 75 | #' update(ptag$display$none, width = "100%") 76 | #' } 77 | #' 78 | #' @import R6 79 | #' @export 80 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81 | Style <- R6::R6Class( 82 | "Style", 83 | 84 | public = list( 85 | selector = NULL, 86 | declarations = NULL, 87 | indent = NULL, 88 | 89 | initialize = function(..., selector = NULL, indent = 0) { 90 | self$indent <- indent 91 | self$set_selector(selector = selector) 92 | self$declarations <- list() 93 | self$update(...) 94 | 95 | invisible(self) 96 | }, 97 | 98 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 99 | # Update and return the selector. 100 | # internal the selector is stored as a 'Selector' object 101 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 | set_selector = function(selector = NULL) { 103 | if (is.null(selector)) { 104 | # do nothing 105 | } else if (is.character(selector)) { 106 | self$selector <- Selector$new(selector) 107 | } else if (inherits(selector, "Selector")) { 108 | self$selector <- selector 109 | } else { 110 | stop("Style$set_selector(): Only understands character strings or Selector objects, not ", class(selector)) 111 | } 112 | invisible(self) 113 | }, 114 | 115 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 116 | # Add declarations which consists of a property and a value 117 | # derived from the named arguments to this method. 118 | # If there any unnamed arguments, then the first one is considered the selector 119 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 | update = function(...) { 121 | varargs <- list(...) 122 | 123 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 124 | # If caller is using the 'prop' helper then these results will contain 125 | # a list nested within the '...' argument. 126 | # So use unlist() to carefully remove one layer of listing 127 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 128 | is_list_element <- vapply(varargs, is.list, logical(1)) 129 | if (any(is_list_element)) { 130 | varargs <- unlist(varargs, recursive = FALSE, use.names = TRUE) 131 | } 132 | 133 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 134 | # If there is a single unnamed argument, then assume it's the 135 | # selector name and remove it from varargs 136 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137 | unnamed_idx <- which(names(varargs) == "") 138 | if (is.null(names(varargs)) && length(varargs) == 1) { 139 | unnamed_idx <- 1 140 | } 141 | if (length(unnamed_idx) == 1) { 142 | self$set_selector(varargs[[unnamed_idx]]) 143 | varargs[unnamed_idx] <- NULL 144 | } 145 | 146 | 147 | is_list_element <- vapply(varargs, is.list, logical(1)) 148 | if (any(is_list_element)) { 149 | stop("Style$update(): only one level of list() elements is undone. i need a better error message", call. = FALSE) 150 | } 151 | 152 | if (!all_named(varargs)) { 153 | stop("All arguments to Style$update() must be named. Got: ", deparse(varargs)) 154 | } 155 | prop_names <- names(varargs) 156 | 157 | # Fix the names for underscores and the spelling of 'colour' 158 | prop_names <- gsub('colour', 'color', prop_names) 159 | prop_names <- gsub("_", "-", prop_names) 160 | varargs <- setNames(varargs, prop_names) 161 | 162 | # pull out the 'transform' and handle it separately 163 | trans <- varargs$transform 164 | varargs$transform <- NULL 165 | 166 | # all other declarations overwrite any existing value 167 | self$declarations <- modifyList(self$declarations, varargs) 168 | 169 | # but the 'transform' declaration appends 170 | if (!is.null(trans)) { 171 | self$declarations$transform <- paste0(c(self$declarations$transform, trans), collapse = " ") 172 | } 173 | 174 | invisible(self) 175 | }, 176 | 177 | 178 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 179 | # Remove properties by name 180 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 181 | remove = function(...) { 182 | self$declarations[as.character(list(...))] <- NULL 183 | }, 184 | 185 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 186 | # Remove the transform 187 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188 | reset_transform = function() { 189 | self$declarations$transform <- NULL 190 | }, 191 | 192 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 193 | # Create character represenation. 194 | # If inline = TRUE, then print on a single line and exclude the selector 195 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 196 | as_character = function(inline = FALSE, ...) { 197 | style_strings <- c() 198 | 199 | if (inline || is.null(self$selector)) { 200 | indent <- '' 201 | spacer <- '' 202 | collapse <- "; " 203 | } else if (self$indent > 0) { 204 | indent <- ' ' 205 | spacer <- ' ' 206 | collapse <- ";\n" 207 | } else { 208 | indent <- '' 209 | spacer <- ' ' 210 | collapse <- ";\n" 211 | } 212 | 213 | prop_names <- names(self$declarations) 214 | 215 | for (i in seq_along(self$declarations)) { 216 | prop_name <- prop_names[i] 217 | value <- self$declarations[[i]] 218 | this_string <- paste0(spacer, prop_name, ": ", value) 219 | style_strings <- c(style_strings, this_string) 220 | } 221 | 222 | style_string <- paste(style_strings, collapse = collapse) 223 | 224 | if (nchar(style_string) > 0) { 225 | style_string <- paste0(style_string, ";") 226 | } 227 | 228 | 229 | if (inline || is.null(self$selector)) { 230 | style_string 231 | } else if (length(self$declarations) == 1) { 232 | paste0(indent, self$selector, " { ", trimws(style_string), " }") 233 | } else { 234 | paste0(indent, self$selector, " {\n", style_string, "\n", indent, "}") 235 | } 236 | }, 237 | 238 | 239 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 240 | # create an inline style string 241 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 242 | as_inline = function(...) { 243 | self$as_character(inline = TRUE, ...) 244 | }, 245 | 246 | 247 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 248 | # Print 249 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 250 | print = function(...) { 251 | cat(self$as_character(...)) 252 | }, 253 | 254 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 255 | # Deep copy needed as object contains R6 object (selector) 256 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 257 | copy = function() { 258 | self$clone(deep = TRUE) 259 | } 260 | ), 261 | 262 | private = list( 263 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 264 | # When called with `$clone(deep = TRUE)`, the 'deep_clone' function is 265 | # called for every name/value pair in the object. 266 | # See: https://r6.r-lib.org/articles/Introduction.html 267 | # Need special handling for: 268 | # - selector 269 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 270 | deep_clone = function(name, value) { 271 | if (name %in% c('selector')) { 272 | if (inherits(value, "R6")) value$clone(deep = TRUE) else value 273 | } else { 274 | value 275 | } 276 | } 277 | ) 278 | ) 279 | 280 | 281 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 282 | #' Retrieve the character representation of a Style object 283 | #' 284 | #' @param x Style object 285 | #' @param ... other arguments 286 | #' 287 | #' @export 288 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 289 | as.character.Style <- function(x, ...) { 290 | x$as_character(...) 291 | } 292 | 293 | 294 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 295 | #' Helper function for creating a Style object for a CSS style (requires selector) 296 | #' 297 | #' @param selector character string or object of Selector class 298 | #' @param ... named list of properties for the style e.g. `color = "black"` 299 | #' 300 | #' @export 301 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 302 | css_style <- function(..., selector = NULL) { 303 | invisible(Style$new(..., selector = selector)) 304 | } 305 | 306 | 307 | -------------------------------------------------------------------------------- /R/StyleSheet.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | #' CSS style sheet builder 5 | #' 6 | #' @docType class 7 | #' 8 | #' @usage NULL 9 | #' @section Usage: 10 | #' \preformatted{sheet <- StyleSheet$new() 11 | #' sheet <- css_stylesheet() 12 | #' 13 | #' sheet$append(style) 14 | #' sheet$remove(3) 15 | #' sheet$add('h1', color = 'blue') 16 | #' sheet$as_character() 17 | #' new_sheet <- sheet$copy() 18 | #' 19 | #' } 20 | #' 21 | #' @format NULL 22 | #' 23 | #' @section Methods: 24 | #' 25 | #' \describe{ 26 | #' 27 | #' \item{\code{$new(...)}}{ 28 | #' Initialise a stylesheet 29 | #' \tabular{ll}{ 30 | #' \code{...} \tab all arguments treated as \code{Style} objects and added to the style sheet \cr 31 | #' } 32 | #'} 33 | #' 34 | #' 35 | #' \item{\code{$append(...)}}{ 36 | #' Append \code{Style} objects to this StyleSheet 37 | #' \tabular{ll}{ 38 | #' \code{...} \tab all arguments treated as Style objects and added to the style sheet \cr 39 | #' } 40 | #' } 41 | #' 42 | #' \item{\code{$remove(indices)}}{ 43 | #' Remove \code{Style} objects from this StyleSheet by index. 44 | #' \tabular{ll}{ 45 | #' \code{indices} \tab indices of Style objects to remove \cr 46 | #' } 47 | #' } 48 | #' 49 | #' \item{\code{$add(..., selector = NULL)}}{ 50 | #' Creates a \code{Style} object and adds it to the StyleSheet. Returns the newly 51 | #' created \code{Style}. 52 | #' \tabular{ll}{ 53 | #' \code{...} \tab name/value properties \cr 54 | #' \code{selector} \tab If given, then used as the the selector for this style. If 55 | #' not given, then the first unnamed argument in \code{...} is interpreted as the 56 | #' character string for the selector. \cr 57 | #' } 58 | #' } 59 | #' 60 | #' \item{\code{$as_character()}}{ 61 | #' Convert \code{StyleSheet} to a character string. 62 | #' } 63 | #' 64 | #' \item{\code{$print()}}{ 65 | #' Print \code{StyleSheet} to terminal. 66 | #' } 67 | #' 68 | #' \item{\code{$copy()}}{ 69 | #' Copy \code{StyleSheet}. 70 | #' } 71 | #' 72 | #'} 73 | #' 74 | #' 75 | #' @examples 76 | #' \dontrun{ 77 | #' marsha <- css_style('#marsha')$ 78 | #' update(marsha = 'marsha')$ 79 | #' update(ptag$display$none, width = "100%") 80 | #' 81 | #' sheet <- StyleSheet$new(marsha) 82 | #' } 83 | #' 84 | #' @import R6 85 | #' @export 86 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 87 | StyleSheet <- R6::R6Class( 88 | "StyleSheet", 89 | public = list( 90 | styles = NULL, 91 | initialize = function(...) { 92 | do.call(self$append, list(...)) 93 | invisible(self) 94 | }, 95 | 96 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 97 | # Append Style objects 98 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 99 | append = function(...) { 100 | new_styles <- list(...) 101 | is_Style <- vapply(new_styles, 102 | function(x) { 103 | inherits(x, 'Style') || inherits(x, 'StyleSheet') 104 | }, 105 | logical(1)) 106 | if (!all(is_Style)) { 107 | stop("StyleSheet$append(): only accepts 'Style' or 'StyleSheet' objects") 108 | } 109 | self$styles <- append(self$styles, new_styles) 110 | 111 | invisible(self) 112 | }, 113 | 114 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 115 | # Remove styles by giving the indices of selectors to remove. 116 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 117 | remove = function(indices) { 118 | self$styles[indices] <- NULL 119 | invisible(self) 120 | }, 121 | 122 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 123 | # Create a Style object, add it it to the current stylesheet and return it. 124 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 125 | add = function(..., selector = NULL) { 126 | this_style <- Style$new(..., selector = selector) 127 | 128 | if (is.null(this_style$selector)) { 129 | stop("StyleSheet$add(): must nominate a selector") 130 | } 131 | 132 | do.call(self$append, list(this_style)) 133 | 134 | invisible(this_style) 135 | }, 136 | 137 | 138 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 139 | # Character representation is a concetentation of all the Style objects 140 | # in self$styles 141 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 142 | as_character = function(...) { 143 | strings <- vapply(self$styles, function(x) {x$as_character()}, character(1)) 144 | paste(strings, collapse = "\n") 145 | }, 146 | 147 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148 | # print 149 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 150 | print = function() { 151 | cat(self$as_character(), "\n") 152 | }, 153 | 154 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 155 | # Deep copy needed as 'styles' is a list of R6 objects 156 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 157 | copy = function() { 158 | self$clone(deep = TRUE) 159 | } 160 | ), 161 | 162 | private = list( 163 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 164 | # When called with `$clone(deep = TRUE)`, the 'deep_clone' function is 165 | # called for every name/value pair in the object. 166 | # See: https://r6.r-lib.org/articles/Introduction.html 167 | # Need special handling for: 168 | # - 'styles' is a list of R6 objects 169 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 170 | deep_clone = function(name, value) { 171 | if (name %in% c('styles')) { 172 | lapply(value, function(x) {if (inherits(x, "R6")) x$clone(deep = TRUE) else x}) 173 | } else { 174 | value 175 | } 176 | } 177 | ) 178 | ) 179 | 180 | 181 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 182 | #' Retrieve the character representation of a SStyleSheettyle object 183 | #' @param x StyleSheet object 184 | #' @param ... other arguments 185 | #' @export 186 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 187 | as.character.StyleSheet <- function(x, ...) { 188 | x$as_character(...) 189 | } 190 | 191 | 192 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 193 | #' @rdname StyleSheet 194 | #' @usage NULL 195 | #' @export 196 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 197 | css_stylesheet <- function(...) { 198 | StyleSheet$new(...) 199 | } 200 | 201 | 202 | -------------------------------------------------------------------------------- /R/aaa.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | # List of all CSS transforms and their arguments 7 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | transform_info <- list( 9 | list(name = "matrix" , units=NULL , args = letters[1:6]), 10 | list(name = "matrix3d" , units=NULL , args = letters[1:16]), 11 | list(name = "none" , units=NULL , args = c()), 12 | list(name = "perspective" , units=NULL , args = 'd'), 13 | list(name = "rotate" , units='deg', args = c('angle')), 14 | list(name = "rotate3d" , units='deg', args = c('x', 'y', 'z', 'angle')), 15 | list(name = "rotateX" , units='deg', args = c('angle')), 16 | list(name = "rotateY" , units='deg', args = c('angle')), 17 | list(name = "rotateZ" , units='deg', args = c('angle')), 18 | list(name = "scale" , units=NULL , args = c('x', 'y')), 19 | list(name = "scale3d" , units=NULL , args = c('x', 'y', 'z')), 20 | list(name = "scaleX" , units=NULL , args = c('x')), 21 | list(name = "scaleY" , units=NULL , args = c('y')), 22 | list(name = "scaleZ" , units=NULL , args = c('z')), 23 | list(name = "skew" , units='deg', args = c('x', 'y')), 24 | list(name = "skewX" , units='deg', args = c('x')), 25 | list(name = "skewY" , units='deg', args = c('y')), 26 | list(name = "translate" , units='px' , args = c('x', 'y')), 27 | list(name = "translate3d" , units='px' , args = c('x', 'y', 'z')), 28 | list(name = "translateX" , units='px' , args = c('x')), 29 | list(name = "translateY" , units='px' , args = c('y')), 30 | list(name = "translateZ" , units='px' , args = c('z')) 31 | ) 32 | 33 | 34 | 35 | # This is list of CSS properties. 36 | # Sourced from the Adobe 'brackets' project 37 | # https://github.com/adobe/brackets/blob/master/src/extensions/default/CSSCodeHints/CSSProperties.json 38 | 39 | properties <- list( 40 | list(name = "align-content" , values = c("center", "flex-end", "flex-start", "space-around", "space-between", "stretch")), 41 | list(name = "align-items" , values = c("baseline", "center", "flex-end", "flex-start", "stretch")), 42 | list(name = "align-self" , values = c("auto", "baseline", "center", "flex-end", "flex-start", "stretch")), 43 | list(name = "all" , values = c()), 44 | list(name = "animation" , values = c()), 45 | list(name = "animation-delay" , values = c()), 46 | list(name = "animation-direction" , values = c("alternate", "alternate-reverse", "normal", "reverse")), 47 | list(name = "animation-duration" , values = c()), 48 | list(name = "animation-fill-mode" , values = c("backwards", "both", "forwards", "none")), 49 | list(name = "animation-iteration-count" , values = "infinite"), 50 | list(name = "animation-name" , values = "none"), 51 | list(name = "animation-play-state" , values = c("paused", "running")), 52 | list(name = "animation-timing-function" , values = c("cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "step-end", "step-start", "steps()")), 53 | list(name = "backface-visibility" , values = c("hidden", "visible")), 54 | list(name = "background" , values = c()), 55 | list(name = "background-attachment" , values = c("fixed", "local", "scroll", "inherit")), 56 | list(name = "background-blend-mode" , values = c("color", "color-burn", "color-dodge", "darken", "difference", "exclusion", "hard-light", "hue", "lighten", "luminosity", "multiply", "normal", "overlay", "saturation", "screen", "soft-light")), 57 | list(name = "background-clip" , values = c("border-box", "content-box", "padding-box", "inherit")), 58 | list(name = "background-color" , values = "inherit"), 59 | list(name = "background-image" , values = c("image()", "linear-gradient()", "radial-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "url()")), 60 | list(name = "background-origin" , values = c("border-box", "content-box", "padding-box", "inherit")), 61 | list(name = "background-position" , values = c("left", "center", "right", "bottom", "top")), 62 | list(name = "background-repeat" , values = c("no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space")), 63 | list(name = "background-size" , values = c("auto", "contain", "cover")), 64 | list(name = "border" , values = c()), 65 | list(name = "border-collapse" , values = c("collapse", "separate", "inherit")), 66 | list(name = "border-color" , values = "inherit"), 67 | list(name = "border-spacing" , values = "inherit"), 68 | list(name = "border-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 69 | list(name = "border-bottom" , values = c()), 70 | list(name = "border-bottom-color" , values = "inherit"), 71 | list(name = "border-bottom-left-radius" , values = c()), 72 | list(name = "border-bottom-right-radius", values = c()), 73 | list(name = "border-bottom-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 74 | list(name = "border-bottom-width" , values = c("medium", "thin", "thick", "inherit")), 75 | list(name = "border-image" , values = "url()"), 76 | list(name = "border-image-outset" , values = c()), 77 | list(name = "border-image-slice" , values = c()), 78 | list(name = "border-image-source" , values = c()), 79 | list(name = "border-image-repeat" , values = c("repeat", "round", "space", "stretch")), 80 | list(name = "border-image-width" , values = "auto"), 81 | list(name = "border-left" , values = c()), 82 | list(name = "border-left-color" , values = "inherit"), 83 | list(name = "border-left-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 84 | list(name = "border-left-width" , values = c("medium", "thin", "thick", "inherit")), 85 | list(name = "border-radius" , values = c()), 86 | list(name = "border-right" , values = c()), 87 | list(name = "border-right-color" , values = "inherit"), 88 | list(name = "border-right-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 89 | list(name = "border-right-width" , values = c("medium", "thin", "thick", "inherit")), 90 | list(name = "border-top" , values = c()), 91 | list(name = "border-top-color" , values = "inherit"), 92 | list(name = "border-top-left-radius" , values = c()), 93 | list(name = "border-top-right-radius" , values = c()), 94 | list(name = "border-top-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 95 | list(name = "border-top-width" , values = c("medium", "thin", "thick", "inherit")), 96 | list(name = "border-width" , values = c("medium", "thin", "thick", "inherit")), 97 | list(name = "box-decoration-break" , values = c("clone", "slice")), 98 | list(name = "box-shadow" , values = c()), 99 | list(name = "box-sizing" , values = c("border-box", "content-box", "inherit")), 100 | list(name = "bottom" , values = c("auto", "inherit")), 101 | list(name = "break-after" , values = c("always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right")), 102 | list(name = "break-before" , values = c("always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right")), 103 | list(name = "break-inside" , values = c("auto", "avoid", "avoid-column", "avoid-page", "avoid-region")), 104 | list(name = "caption-side" , values = c("bottom", "top", "inherit")), 105 | list(name = "caret-color" , values = "auto"), 106 | list(name = "clear" , values = c("both", "left", "none", "right", "inherit")), 107 | list(name = "clip" , values = c("auto", "inherit")), 108 | list(name = "color" , values = "inherit"), 109 | list(name = "columns" , values = c()), 110 | list(name = "column-count" , values = c()), 111 | list(name = "column-fill" , values = c("auto", "balance")), 112 | list(name = "column-gap" , values = "normal"), 113 | list(name = "column-rule" , values = c()), 114 | list(name = "column-rule-color" , values = c()), 115 | list(name = "column-rule-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 116 | list(name = "column-rule-width" , values = c("medium", "thin", "thick", "inherit")), 117 | list(name = "column-span" , values = c("all", "none")), 118 | list(name = "column-width" , values = c("auto", "inherit")), 119 | list(name = "content" , values = c("attr()", "close-quote", "no-close-quote", "no-open-quote", "normal", "none", "open-quote", "inherit")), 120 | list(name = "counter-increment" , values = c("none", "inherit")), 121 | list(name = "counter-reset" , values = c("none", "inherit")), 122 | list(name = "cursor" , values = c("alias", "all-scroll", "auto", "cell", "col-resize", "context-menu", "copy", "crosshair", "default", "e-resize", "ew-resize", "grab", "grabbing", "help", "inherit", "move", "n-resize", "ne-resize", "nesw-resize", "no-drop", "none", "not-allowed", "ns-resize", "nw-resize", "nwse-resize", "pointer", "progress", "row-resize", "s-resize", "se-resize", "sw-resize", "text", "vertical-text", "w-resize", "wait", "zoom-in", "zoom-out")), 123 | list(name = "direction" , values = c("ltr", "rtl", "inherit")), 124 | list(name = "display" , values = c("block", "contents", "flex", "flow-root", "grid", "inline", "inline-block", "inline-flex", "inline-grid", "inline-table", "list-item", "none", "run-in", "subgrid", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "inherit")), 125 | list(name = "empty-cells" , values = c("hide", "show", "inherit")), 126 | list(name = "filter" , values = c("blur()", "brightness()", "contrast()", "custom()", "drop-shadow()", "grayscale()", "hue-rotate()", "invert()", "none", "opacity()", "sepia()", "saturate()", "url()")), 127 | list(name = "flex" , values = c("auto", "initial", "none")), 128 | list(name = "flex-basis" , values = "auto"), 129 | list(name = "flex-direction" , values = c("column", "column-reverse", "row", "row-reverse")), 130 | list(name = "flex-flow" , values = c("column", "column-reverse", "nowrap", "row", "row-reverse", "wrap", "wrap-reverse")), 131 | list(name = "flex-grow" , values = c()), 132 | list(name = "flex-shrink" , values = c()), 133 | list(name = "flex-wrap" , values = c("nowrap", "wrap", "wrap-reverse")), 134 | list(name = "float" , values = c("left", "right", "none", "inherit")), 135 | list(name = "flow-into" , values = "none"), 136 | list(name = "flow-from" , values = c("none", "inherit")), 137 | list(name = "font" , values = c()), 138 | list(name = "font-display" , values = c("auto", "block", "swap", "fallback", "optional")), 139 | list(name = "font-family" , values = c("cursive", "fantasy", "inherit", "monospace", "sans-serif", "serif")), 140 | list(name = "font-feature-settings" , values = "normal"), 141 | list(name = "font-kerning" , values = c("auto", "none", "normal")), 142 | list(name = "font-language-override" , values = "normal"), 143 | list(name = "font-size" , values = c()), 144 | list(name = "font-size-adjust" , values = c("auto", "none")), 145 | list(name = "font-stretch" , values = c("condensed", "expanded", "extra-condensed", "extra-expanded", "normal", "semi-condensed", "semi-expanded", "ultra-condensed", "ultra-expanded")), 146 | list(name = "font-style" , values = c("italic", "normal", "oblique")), 147 | list(name = "font-synthesis" , values = c("none", "style", "weight")), 148 | list(name = "font-variant" , values = c("normal", "small-caps", "inherit")), 149 | list(name = "font-variant-alternates" , values = "normal"), 150 | list(name = "font-variant-caps" , values = c("normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps")), 151 | list(name = "font-variant-east-asian" , values = "normal"), 152 | list(name = "font-variant-ligatures" , values = c("normal", "none")), 153 | list(name = "font-variant-numeric" , values = "normal"), 154 | list(name = "font-variant-position" , values = c("normal", "sub", "super")), 155 | list(name = "font-weight" , values = c("bold", "bolder", "lighter", "normal", "100", "200", "300", "400", "500", "600", "700", "800", "900", "inherit")), 156 | list(name = "grid" , values = c()), 157 | list(name = "grid-area" , values = c()), 158 | list(name = "grid-auto-columns" , values = c()), 159 | list(name = "grid-auto-flow" , values = c("row", "column", "dense")), 160 | list(name = "grid-auto-rows" , values = c()), 161 | list(name = "grid-column" , values = "auto"), 162 | list(name = "grid-column-end" , values = c()), 163 | list(name = "grid-column-gap" , values = c()), 164 | list(name = "grid-column-start" , values = c()), 165 | list(name = "grid-gap" , values = c()), 166 | list(name = "grid-row" , values = "auto"), 167 | list(name = "grid-row-end" , values = c()), 168 | list(name = "grid-row-start" , values = c()), 169 | list(name = "grid-row-gap" , values = c()), 170 | list(name = "grid-template" , values = "none"), 171 | list(name = "grid-template-areas" , values = c()), 172 | list(name = "grid-template-columns" , values = "auto"), 173 | list(name = "grid-template-rows" , values = "auto"), 174 | list(name = "hanging-punctuation" , values = c("allow-end", "first", "force-end", "last", "none")), 175 | list(name = "height" , values = c("auto", "inherit")), 176 | list(name = "hyphens" , values = c("auto", "manual", "none")), 177 | list(name = "image-orientation" , values = c()), 178 | list(name = "image-resolution" , values = c("from-image", "snap")), 179 | list(name = "isolation" , values = c("auto", "isolate")), 180 | list(name = "justify-content" , values = c("center", "flex-end", "flex-start", "space-around", "space-between")), 181 | list(name = "left" , values = c("auto", "inherit")), 182 | list(name = "letter-spacing" , values = c("normal", "inherit")), 183 | list(name = "line-height" , values = c("normal", "inherit")), 184 | list(name = "list-style" , values = c("none", "inherit", "initial", "unset", "url()", "armenian", "circle", "decimal", "decimal-leading-zero", "disc", "georgian", "inside", "lower-alpha", "lower-greek", "lower-latin", "lower-roman", "outside", "square", "upper-alpha", "upper-latin", "upper-roman")), 185 | list(name = "list-style-image" , values = c("none", "url()", "inherit")), 186 | list(name = "list-style-position" , values = c("inside", "outside", "inherit")), 187 | list(name = "list-style-type" , values = c("armenian", "circle", "decimal", "decimal-leading-zero", "disc", "georgian", "lower-alpha", "lower-greek", "lower-latin", "lower-roman", "none", "square", "upper-alpha", "upper-latin", "upper-roman", "inherit")), 188 | list(name = "margin" , values = c("auto", "inherit")), 189 | list(name = "margin-bottom" , values = c("auto", "inherit")), 190 | list(name = "margin-left" , values = c("auto", "inherit")), 191 | list(name = "margin-right" , values = c("auto", "inherit")), 192 | list(name = "margin-top" , values = c("auto", "inherit")), 193 | list(name = "max-height" , values = c("none", "inherit")), 194 | list(name = "max-width" , values = c("none", "inherit")), 195 | list(name = "min-height" , values = "inherit"), 196 | list(name = "min-width" , values = "inherit"), 197 | list(name = "mix-blend-mode" , values = c("color", "color-burn", "color-dodge", "darken", "difference", "exclusion", "hard-light", "hue", "lighten", "luminosity", "multiply", "normal", "overlay", "saturation", "screen", "soft-light")), 198 | list(name = "object-fit" , values = c("contain", "cover", "fill", "none", "scale-down")), 199 | list(name = "object-position" , values = c("left", "center", "right", "bottom", "top")), 200 | list(name = "opacity" , values = "inherit"), 201 | list(name = "order" , values = c()), 202 | list(name = "orphans" , values = "inherit"), 203 | list(name = "outline" , values = "inherit"), 204 | list(name = "outline-color" , values = c("invert", "inherit")), 205 | list(name = "outline-offset" , values = "inherit"), 206 | list(name = "outline-style" , values = c("dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit")), 207 | list(name = "outline-width" , values = c("medium", "thin", "thick", "inherit")), 208 | list(name = "overflow" , values = c("auto", "hidden", "scroll", "visible", "inherit")), 209 | list(name = "overflow-x" , values = c("auto", "hidden", "scroll", "visible", "inherit")), 210 | list(name = "overflow-y" , values = c("auto", "hidden", "scroll", "visible", "inherit")), 211 | list(name = "padding" , values = "inherit"), 212 | list(name = "padding-bottom" , values = c()), 213 | list(name = "padding-left" , values = c()), 214 | list(name = "padding-right" , values = c()), 215 | list(name = "padding-top" , values = c()), 216 | list(name = "page-break-after" , values = c("always", "auto", "avoid", "left", "right", "inherit")), 217 | list(name = "page-break-before" , values = c("always", "auto", "avoid", "left", "right", "inherit")), 218 | list(name = "page-break-inside" , values = c("auto", "avoid", "inherit")), 219 | list(name = "perspective" , values = "none"), 220 | list(name = "perspective-origin" , values = c("bottom", "center", "left", "right", "top")), 221 | list(name = "pointer-events" , values = c("all", "auto", "fill", "inherit", "none", "painted", "stroke", "visible", "visibleFill", "visiblePainted", "visibleStroke")), 222 | list(name = "position" , values = c("absolute", "fixed", "relative", "static", "sticky", "inherit")), 223 | list(name = "quotes" , values = c("none", "inherit")), 224 | list(name = "region-break-after" , values = c("always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right")), 225 | list(name = "region-break-before" , values = c("always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right")), 226 | list(name = "region-break-inside" , values = c("auto", "avoid", "avoid-column", "avoid-page", "avoid-region")), 227 | list(name = "region-fragment" , values = c("auto", "break")), 228 | list(name = "resize" , values = c("both", "horizontal", "none", "vertical", "inherit")), 229 | list(name = "right" , values = c("auto", "inherit")), 230 | list(name = "scroll-behavior" , values = c("auto", "smooth")), 231 | list(name = "src" , values = "url()"), 232 | list(name = "shape-image-threshold" , values = c()), 233 | list(name = "shape-inside" , values = c("auto", "circle()", "ellipse()", "inherit", "outside-shape", "polygon()", "rectangle()")), 234 | list(name = "shape-margin" , values = c()), 235 | list(name = "shape-outside" , values = c("none", "inherit", "circle()", "ellipse()", "polygon()", "inset()", "margin-box", "border-box", "padding-box", "content-box", "url()", "image()", "linear-gradient()", "radial-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()")), 236 | list(name = "tab-size" , values = c()), 237 | list(name = "table-layout" , values = c("auto", "fixed", "inherit")), 238 | list(name = "text-align" , values = c("start", "end", "center", "left", "justify", "right", "match-parent", "justify-all", "inherit")), 239 | list(name = "text-align-last" , values = c("center", "left", "justify", "right", "inherit")), 240 | list(name = "text-decoration" , values = c("line-through", "none", "overline", "underline", "inherit")), 241 | list(name = "text-decoration-color" , values = c()), 242 | list(name = "text-decoration-line" , values = c("line-through", "none", "overline", "underline")), 243 | list(name = "text-decoration-skip" , values = c("edges", "ink", "none", "objects", "spaces")), 244 | list(name = "text-decoration-style" , values = c("dashed", "dotted", "double", "solid", "wavy")), 245 | list(name = "text-emphasis" , values = c()), 246 | list(name = "text-emphasis-color" , values = c()), 247 | list(name = "text-emphasis-position" , values = c("above", "below", "left", "right")), 248 | list(name = "text-emphasis-style" , values = c("circle", "dot", "double-circle", "filled", "none", "open", "sesame", "triangle")), 249 | list(name = "text-indent" , values = "inherit"), 250 | list(name = "text-justify" , values = c("auto", "none", "inter-word", "inter-character", "inherit")), 251 | list(name = "text-overflow" , values = c("clip", "ellipsis", "inherit")), 252 | list(name = "text-shadow" , values = c()), 253 | list(name = "text-rendering" , values = c("auto", "geometricPrecision", "optimizeLegibility", "optimizeSpeed")), 254 | list(name = "text-transform" , values = c("capitalize", "full-width", "lowercase", "none", "uppercase", "inherit")), 255 | list(name = "text-underline-position" , values = c("alphabetic", "auto", "below", "left", "right")), 256 | list(name = "top" , values = c("auto", "inherit")), 257 | list(name = "transform" , values = c("matrix()", "matrix3d()", "none", "perspective()", "rotate()", "rotate3d()", "rotateX()", "rotateY()", "rotateZ()", "scale()", "scale3d()", "scaleX()", "scaleY()", "scaleZ()", "skewX()", "skewY()", "translate()", "translate3d()", "translateX()", "translateY()", "translateZ()")), 258 | list(name = "transform-origin" , values = c("bottom", "center", "left", "right", "top")), 259 | list(name = "transform-style" , values = c("flat", "preserve-3d")), 260 | list(name = "transition" , values = c()), 261 | list(name = "transition-delay" , values = c()), 262 | list(name = "transition-duration" , values = c()), 263 | list(name = "transition-property" , values = c("all", "none")), 264 | list(name = "transition-timing-function", values = c("cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "step-end", "step-start", "steps()")), 265 | list(name = "unicode-bidi" , values = c("bidi-override", "embed", "normal", "inherit")), 266 | list(name = "unicode-range" , values = c()), 267 | list(name = "user-select" , values = c("all", "auto", "contain", "none", "text")), 268 | list(name = "vertical-align" , values = c("baseline", "bottom", "middle", "sub", "super", "text-bottom", "text-top", "top", "inherit")), 269 | list(name = "visibility" , values = c("collapse", "hidden", "visible", "inherit")), 270 | list(name = "white-space" , values = c("normal", "nowrap", "pre", "pre-line", "pre-wrap", "inherit")), 271 | list(name = "widows" , values = "inherit"), 272 | list(name = "width" , values = c("auto", "inherit")), 273 | list(name = "will-change" , values = c("auto", "contents", "opacity", "scroll-position", "transform", "inherit", "initial", "unset")), 274 | list(name = "word-break" , values = c("normal", "break-all", "keep-all")), 275 | list(name = "word-spacing" , values = c("normal", "inherit")), 276 | list(name = "word-wrap" , values = c("break-word", "normal")), 277 | list(name = "z-index" , values = c("auto", "inherit")) 278 | ) 279 | -------------------------------------------------------------------------------- /R/prop.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | # Create a function with the given arguments that simply returns the first 7 | # argument value. all args are included for auto-complete during coding 8 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | create_first_arg_func <- function(name) { 10 | fstring <- glue("function(value) {{ 11 | res <- setNames(list(value), name) 12 | class(res) <- c('css_property') 13 | res 14 | }}") 15 | 16 | eval(parse(text = fstring)) 17 | } 18 | 19 | 20 | 21 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | # Some magic to create the property helper 23 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 | create_inner_inner <- function(value, name) { 25 | res <- setNames(list(value), name) 26 | class(res) <- c('css_property') 27 | res 28 | } 29 | 30 | create_inner <- function(prop) { 31 | res <- lapply( 32 | prop$values, 33 | create_inner_inner, prop$name 34 | ) 35 | 36 | res <- setNames(res, prop$values) 37 | res$set <- create_first_arg_func(prop$name) 38 | 39 | res 40 | } 41 | 42 | 43 | 44 | prop_names <- vapply(properties, function(x) {x$name}, character(1)) 45 | inners <- lapply(properties, create_inner) 46 | 47 | 48 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 | #' CSS property helper 50 | #' 51 | #' Uses autocomplete to help write some standard propertys 52 | #' 53 | #' @importFrom stats setNames 54 | #' @import glue 55 | #' @export 56 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 57 | css_prop <- setNames(inners, prop_names) 58 | 59 | 60 | 61 | 62 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 63 | #' Convert a CSS 'property' object to a string 64 | #' 65 | #' @param x property object 66 | #' @param ... other arguments 67 | #' 68 | #' @export 69 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 70 | as.character.css_property <- function(x, ...) { 71 | paste0(names(x), ": ", unname(unlist(x)), ";") 72 | } 73 | 74 | 75 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 76 | #' Print a CSS 'property' object 77 | #' 78 | #' @param x property object 79 | #' @param ... other arguments 80 | #' 81 | #' @export 82 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 83 | print.css_property <- function(x, ...) { 84 | cat(as.character(x), "\n", sep = "") 85 | } 86 | 87 | 88 | 89 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | #' Helper to manually create new "!important" properies 91 | #' 92 | #' @param ... a name/value pair 93 | #' 94 | #' @export 95 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 96 | imp <- function(...) { 97 | 98 | ll <- list(...) 99 | 100 | if (inherits(ll[[1]], 'css_property')) { 101 | res <- ll[[1]] 102 | res[[1]] <- paste(res[[1]], "!important") 103 | return(res) 104 | } 105 | 106 | value <- unname(ll[[1]]) 107 | name <- names(ll)[1] 108 | value <- paste(value, "!important") 109 | res <- setNames(list(value), name) 110 | class(res) <- c('css_property') 111 | res 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /R/prop_animation.R: -------------------------------------------------------------------------------- 1 | 2 | # MDN animation reference: https://developer.mozilla.org/en-US/docs/Web/CSS/animation 3 | 4 | css_anim_defaults <- list( 5 | name = 'none', 6 | duration = "0s", 7 | timing_function = 'ease', 8 | delay = "0s", 9 | iteration_count = 1, 10 | direction = 'normal', 11 | fill_mode = 'none', 12 | play_state = 'running' 13 | ) 14 | 15 | 16 | 17 | css_prop$animation <- function( 18 | name = 'none', 19 | duration = 10, 20 | timing_function = c('ease', 'ease-in', 'ease-out', 'ease-in-out', 21 | 'linear', 'step-start', 'step-end'), 22 | delay = 0, 23 | iteration_count = 'infinite', 24 | direction = c('normal', 'reverse', 'alternate', 'alternate-reverse'), 25 | fill_mode = c('none', 'forwards', 'backwards', 'both'), 26 | play_state = c('running', 'paused') 27 | ) { 28 | 29 | # Specify duration and delay in seconds 30 | if (is.numeric(duration) || !endsWith(duration, 's') || !endsWith(duration, 'S')) { 31 | duration <- paste0(duration, 's') 32 | } 33 | 34 | if (is.numeric(delay) || !endsWith(delay, 's') || !endsWith(delay, 'S')) { 35 | delay <- paste0(delay, 's') 36 | } 37 | 38 | # Assemble the list of all options 39 | this_anim <- list( 40 | name = name, 41 | duration = duration, 42 | timing_function = match.arg(timing_function), 43 | delay = delay, 44 | iteration_count = iteration_count, 45 | direction = match.arg(direction), 46 | fill_mode = match.arg(fill_mode), 47 | play_state = match.arg(play_state) 48 | ) 49 | 50 | # Keep only those options which are different from the CSS default standard 51 | nn <- names(css_anim_defaults) 52 | is_default <- vapply(nn, function(x) {identical(css_anim_defaults[[x]], this_anim[[x]])}, logical(1)) 53 | this_anim <- this_anim[nn[!is_default]] 54 | 55 | # Create and return the animation property 56 | opts <- c( 57 | this_anim$name, 58 | this_anim$duration, 59 | this_anim$timing_function, 60 | this_anim$delay, 61 | this_anim$iteration_count, 62 | this_anim$direction, 63 | this_anim$fill_mode, 64 | this_anim$play_state 65 | ) 66 | 67 | res <- paste(opts, collapse = " ") 68 | res <- setNames(list(res), 'animation') 69 | class(res) <- 'css_property' 70 | 71 | res 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /R/prop_transform.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | # The properties for transform objects are different from other properties. 5 | # 6 | # Most other properties are simple name/value pairs e.g. "color: #000", but 7 | # transforms are more like name/function-call pairs. 8 | # 9 | # 10 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | 13 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | # Create a function to create a transform property 15 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | create_transform_func <- function(spec) { 17 | args <- spec$args 18 | name <- spec$name 19 | 20 | if (length(args) == 0) { 21 | inner_args <- '' 22 | } else if (name == 'rotate3d') { 23 | inner_args <- paste0("({x} {y} {z} {angle}{unit})") 24 | } else if (!is.null(spec$units)) { 25 | inner_args <- paste0(paste0("{", args, "}"), "{unit}", collapse = " ") 26 | inner_args <- paste0("(", inner_args, ")") 27 | } else { 28 | inner_args <- paste0(paste0("{", args, "}"), collapse = " ") 29 | inner_args <- paste0("(", inner_args, ")") 30 | } 31 | 32 | if (!is.null(spec$units)) { 33 | outer_args <- c(args, glue("unit='{spec$units}'")) 34 | } else { 35 | outer_args <- args 36 | } 37 | 38 | outer_args <- paste0(outer_args, collapse = ", ") 39 | func_string <- glue("function({outer_args}) {{ 40 | res <- list(transform = glue('{name}{inner_args}')) 41 | class(res) <- 'css_property' 42 | res 43 | }}") 44 | 45 | eval(parse(text = func_string)) 46 | } 47 | 48 | 49 | 50 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | # create all the transform-property creator functions 52 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | transform_names <- lapply(transform_info, function(x) x$name) 54 | css_prop$transform <- setNames(lapply(transform_info, create_transform_func), transform_names) 55 | 56 | 57 | 58 | 59 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 | # Create a function to create a transform property 61 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 62 | create_transform_method <- function(spec) { 63 | args <- spec$args 64 | name <- spec$name 65 | 66 | if (length(args) == 0) { 67 | inner_args <- '' 68 | } else if (name == 'rotate3d') { 69 | inner_args <- paste0("({x} {y} {z} {angle}{unit})") 70 | } else if (!is.null(spec$units)) { 71 | inner_args <- paste0(paste0("{", args, "}"), "{unit}", collapse = " ") 72 | inner_args <- paste0("(", inner_args, ")") 73 | } else { 74 | inner_args <- paste0(paste0("{", args, "}"), collapse = " ") 75 | inner_args <- paste0("(", inner_args, ")") 76 | } 77 | 78 | if (!is.null(spec$units)) { 79 | outer_args <- c(args, glue("unit='{spec$units}'")) 80 | } else { 81 | outer_args <- args 82 | } 83 | 84 | self <- NULL 85 | 86 | outer_args <- paste0(outer_args, collapse = ", ") 87 | func_string <- glue("function({outer_args}) {{ 88 | self$update(transform = glue('{name}{inner_args}')) 89 | invisible(self) 90 | }}") 91 | 92 | eval(parse(text = func_string)) 93 | } 94 | 95 | 96 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 97 | # Add a method for each transform to the style object 98 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 99 | for (spec in transform_info) { 100 | 101 | meth <- create_transform_method(spec) 102 | 103 | Style$set("public", spec$name, meth) 104 | } 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /R/utils-multi-args.R: -------------------------------------------------------------------------------- 1 | 2 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | # Stolen from ggplot. used with themes to boil down a long 4 | # argument list to just those values which were used in the function call 5 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | modify_list <- function (old, new) { 7 | for (i in names(new)) old[[i]] <- new[[i]] 8 | old 9 | } 10 | 11 | is_missing_arg <- function (x) identical(x, quote(expr = )) 12 | 13 | find_args <- function (...) { 14 | env <- parent.frame() 15 | args <- names(formals(sys.function(sys.parent(1)))) 16 | vals <- mget(args, envir = env) 17 | vals <- vals[!vapply(vals, is_missing_arg, logical(1))] 18 | modify_list(vals, list(..., ... = NULL)) 19 | } -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | '%||%' <- function(x, y) { 4 | if (is.null(x)) { 5 | y 6 | } else { 7 | x 8 | } 9 | } 10 | 11 | 12 | 13 | 14 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | #' Check if all elements are named 16 | #' 17 | #' @param x object e.g. list, vector 18 | #' @return TRUE if all elements are named, otherwise FALSE 19 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | all_named <- function(x) { 21 | named <- nzchar(names(x)) 22 | length(x) == 0 || (!is.null(named) && length(named) > 0 && all(named)) 23 | } -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = FALSE, 10 | comment = "=> ", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | 15 | library(glue) 16 | library(minicss) 17 | library(htmltools) 18 | ``` 19 | 20 | ```{r echo = FALSE, eval = FALSE} 21 | # Quick logo generation. Borrowed heavily from Nick Tierney's Syn logo process 22 | library(magick) 23 | library(showtext) 24 | font_add_google("Abril Fatface", "gf") 25 | 26 | 27 | # pkgdown::build_site(override = list(destination = "../coolbutuseless.github.io/package/minicss")) 28 | ``` 29 | 30 | 31 | ```{r echo = FALSE, eval = FALSE} 32 | img <- image_read("man/figures/mini-cooper-s.gif") %>% 33 | image_transparent(color = "#f9fafb", fuzz = 10) %>% 34 | image_trim() %>% 35 | image_threshold() 36 | 37 | 38 | hexSticker::sticker(subplot = img, 39 | s_x = 0.92, 40 | s_y = 1.2, 41 | s_width = 1.5, 42 | s_height = 0.95, 43 | package = "css", 44 | p_x = 1, 45 | p_y = 0.5, 46 | p_color = "#223344", 47 | p_family = "gf", 48 | p_size = 11, 49 | h_size = 1.2, 50 | h_fill = "#ffffff", 51 | h_color = "#223344", 52 | filename = "man/figures/logo.png") 53 | 54 | image_read("man/figures/logo.png") 55 | ``` 56 | 57 | 58 | # minicss 59 | 60 | 61 | ![](http://img.shields.io/badge/cool-useless-green.svg) 62 | ![](http://img.shields.io/badge/mini-verse-blue.svg) 63 | ![](http://img.shields.io/badge/very-experimental-orange.svg) 64 | [![Travis build status](https://travis-ci.org/coolbutuseless/minicss.svg?branch=master)](https://travis-ci.org/coolbutuseless/minicss) 65 | 66 | 67 | The goal of `minicss` is to be able to programatically create CSS styles and style sheets 68 | from within R. 69 | 70 | `minicss` objects and output are compabile with Shiny (see the [vignette](https://coolbutuseless.github.io/package/minicss/articles/shiny.html)) 71 | 72 | 73 | ## Overview 74 | 75 | `minicss` is a collection of R6 objects a user creates and encapsulates within 76 | one other to build CSS style sheets 77 | 78 | 79 | | Need to build... | R6 object | alternate initialisation | 80 | |----------------------|--------------------|--------------------------| 81 | | CSS Properties | | `css_prop` | 82 | | CSS Selectors | `Selector$new()` | `css_sel()` | 83 | | KeyFrames | `Keyframe$new()` | `css_keyframe()` | 84 | | | `Keyframes$new()` | `css_keyframes()` | 85 | | CSS Styles | `Style$new()` | `css_style()` | 86 | | CSS Style Sheets | `StyleSheet$new()` | `css_stylesheet()` | 87 | 88 | 89 | ### Quick examples 90 | 91 | 92 | | CSS Entity | code | result | 93 | |---------------|--------------------------------------------|----------------------------| 94 | | Properties | `css_prop$'font-family'$cursive` | `font-family: cursive;` | 95 | | | `css_prop$'animation-delay'$set(12)` | `animation-delay: 12;` | 96 | | Selectors | `css_sel('#cindy')$child_of('#carol')` | `#carol > #cindy` | 97 | | Inline Styles | `css_style(colour='red')$update(margin=0)` | `color: red; margin: 0;` | 98 | | CSS Styles | `css_style(".red", colour='red', width='100%')` | `.red { color: red; width: 100% }` | 99 | | | `css_style(".big", css_prop$'font-size'$set('12px'))` | `.big { font-size: 12px; }` | 100 | | Style Sheets | `css_stylesheet(style1, style2)` | `.style1 {color:red;} .style2{color:blue;}` | 101 | 102 | 103 | ## Installation 104 | 105 | You can install the development version from [GitHub](https://github.com/coolbutuseless/minicss) with: 106 | 107 | ``` r 108 | # install.packages("devtools") 109 | devtools::install_github("coolbutuseless/minicss") 110 | ``` 111 | 112 | 113 | ## Future 114 | 115 | The CSS specification is a bit wart-y, 116 | so there are plenty of weird cases that need to be explicitly handled. Some of 117 | these cases are currently handled by `minicss`, and I'll add others as 118 | they're needed. 119 | 120 | 121 | ## Vignettes 122 | 123 | 124 | * [CSS Selectors](https://coolbutuseless.github.io/package/minicss/articles/Selectors.html) 125 | * [CSS Property helper `css_prop`](https://coolbutuseless.github.io/package/minicss/articles/Properties.html) 126 | * [Styles](https://coolbutuseless.github.io/package/minicss/articles/Styles.html) 127 | * [StyleSheets](https://coolbutuseless.github.io/package/minicss/articles/StyleSheets.html) 128 | * [Keyframes and Animation](https://coolbutuseless.github.io/package/minicss/articles/animation.html) 129 | 130 | 131 | 132 | 133 | ### Example: All-in-one example 134 | 135 | 136 | ```{r} 137 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 138 | # Build some selectors 139 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 140 | sel1 <- Selector$new('h1')$class('demo') 141 | sel2 <- css_sel("h2")$class('highlight') 142 | 143 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 144 | # Build some keyframes for animating elements 145 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 146 | kf1 <- Keyframe$new('from', color = '#123456') 147 | kf2 <- css_keyframe('to', color = '#1289ae')$translateX(10, 'px') 148 | keyframes <- Keyframes$new("pulser", kf1, kf2) 149 | 150 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 151 | # Build some styles 152 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 153 | style1 <- Style$new( 154 | sel1, 155 | css_prop$animation(name = 'pulser', duration = 0.8, direction = 'alternate') 156 | ) 157 | style2 <- Style$new('.mini', background_color = 'green') 158 | style3 <- Style$new(sel2, css_prop$`text-decoration`$underline) 159 | 160 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 161 | # Create a style sheet 162 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 163 | stylesheet <- css_stylesheet(style1, style2, style3, keyframes) 164 | 165 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 166 | # Change my mind about the background colour of 'style2' 167 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 168 | style2$update(background_colour = '#a0a0ff') 169 | 170 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 171 | # Create an inline style 172 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 173 | inline_style <- Style$new(border = "1px solid #123456")$ 174 | update(width = "50%", padding = '10px')$ 175 | as_inline() 176 | 177 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 178 | # Insert the stylesheet in an example HTML document 179 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 180 | html <- glue::glue(" 181 | 182 | 183 | Example 184 | 187 | 188 | 189 |
190 |

Hello #Rstats

191 |

A minicss demo!

192 | This is an example of using minicss to manipulate CSS. 193 |
194 | 195 | ") 196 | ``` 197 | 198 | ```{r echo = FALSE} 199 | html 200 | ``` 201 | 202 | 203 | ```{r echo = FALSE, eval = FALSE} 204 | html 205 | htmltools::browsable(HTML(html)) 206 | ``` 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # minicss 5 | 6 | 7 | 8 | ![](http://img.shields.io/badge/cool-useless-green.svg) 9 | ![](http://img.shields.io/badge/mini-verse-blue.svg) 10 | ![](http://img.shields.io/badge/very-experimental-orange.svg) [![Travis 11 | build 12 | status](https://travis-ci.org/coolbutuseless/minicss.svg?branch=master)](https://travis-ci.org/coolbutuseless/minicss) 13 | 14 | 15 | The goal of `minicss` is to be able to programatically create CSS styles 16 | and style sheets from within R. 17 | 18 | `minicss` objects and output are compabile with Shiny (see the 19 | [vignette](https://coolbutuseless.github.io/package/minicss/articles/shiny.html)) 20 | 21 | ## Overview 22 | 23 | `minicss` is a collection of R6 objects a user creates and encapsulates 24 | within one other to build CSS style sheets 25 | 26 | | Need to build… | R6 object | alternate initialisation | 27 | | ---------------- | ------------------ | ------------------------ | 28 | | CSS Properties | | `css_prop` | 29 | | CSS Selectors | `Selector$new()` | `css_sel()` | 30 | | KeyFrames | `Keyframe$new()` | `css_keyframe()` | 31 | | | `Keyframes$new()` | `css_keyframes()` | 32 | | CSS Styles | `Style$new()` | `css_style()` | 33 | | CSS Style Sheets | `StyleSheet$new()` | `css_stylesheet()` | 34 | 35 | ### Quick examples 36 | 37 | | CSS Entity | code | result | 38 | | ------------- | ----------------------------------------------------- | -------------------------------------------- | 39 | | Properties | `css_prop$'font-family'$cursive` | `font-family: cursive;` | 40 | | | `css_prop$'animation-delay'$set(12)` | `animation-delay: 12;` | 41 | | Selectors | `css_sel('#cindy')$child_of('#carol')` | `#carol > #cindy` | 42 | | Inline Styles | `css_style(colour='red')$update(margin=0)` | `color: red; margin: 0;` | 43 | | CSS Styles | `css_style(".red", colour='red', width='100%')` | `.red { color: red; width: 100% }` | 44 | | | `css_style(".big", css_prop$'font-size'$set('12px'))` | `.big { font-size: 12px; }` | 45 | | Style Sheets | `css_stylesheet(style1, style2)` | `.style1 {color:red;} .style2{color:blue;}` | 46 | 47 | ## Installation 48 | 49 | You can install the development version from 50 | [GitHub](https://github.com/coolbutuseless/minicss) with: 51 | 52 | ``` r 53 | # install.packages("devtools") 54 | devtools::install_github("coolbutuseless/minicss") 55 | ``` 56 | 57 | ## Future 58 | 59 | The CSS specification is a bit wart-y, so there are plenty of weird 60 | cases that need to be explicitly handled. Some of these cases are 61 | currently handled by `minicss`, and I’ll add others as they’re needed. 62 | 63 | ## Vignettes 64 | 65 | - [CSS 66 | Selectors](https://coolbutuseless.github.io/package/minicss/articles/Selectors.html) 67 | - [CSS Property helper 68 | `css_prop`](https://coolbutuseless.github.io/package/minicss/articles/Properties.html) 69 | - [Styles](https://coolbutuseless.github.io/package/minicss/articles/Styles.html) 70 | - [StyleSheets](https://coolbutuseless.github.io/package/minicss/articles/StyleSheets.html) 71 | - [Keyframes and 72 | Animation](https://coolbutuseless.github.io/package/minicss/articles/animation.html) 73 | 74 | ### Example: All-in-one example 75 | 76 | ``` r 77 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 78 | # Build some selectors 79 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 80 | sel1 <- Selector$new('h1')$class('demo') 81 | sel2 <- css_sel("h2")$class('highlight') 82 | 83 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 84 | # Build some keyframes for animating elements 85 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 86 | kf1 <- Keyframe$new('from', color = '#123456') 87 | kf2 <- css_keyframe('to', color = '#1289ae')$translateX(10, 'px') 88 | keyframes <- Keyframes$new("pulser", kf1, kf2) 89 | 90 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 91 | # Build some styles 92 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 | style1 <- Style$new( 94 | sel1, 95 | css_prop$animation(name = 'pulser', duration = 0.8, direction = 'alternate') 96 | ) 97 | style2 <- Style$new('.mini', background_color = 'green') 98 | style3 <- Style$new(sel2, css_prop$`text-decoration`$underline) 99 | 100 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 101 | # Create a style sheet 102 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 | stylesheet <- css_stylesheet(style1, style2, style3, keyframes) 104 | 105 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 106 | # Change my mind about the background colour of 'style2' 107 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 | style2$update(background_colour = '#a0a0ff') 109 | 110 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 111 | # Create an inline style 112 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 113 | inline_style <- Style$new(border = "1px solid #123456")$ 114 | update(width = "50%", padding = '10px')$ 115 | as_inline() 116 | 117 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 118 | # Insert the stylesheet in an example HTML document 119 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 | html <- glue::glue(" 121 | 122 | 123 | Example 124 | 127 | 128 | 129 |
130 |

Hello #Rstats

131 |

A minicss demo!

132 | This is an example of using minicss to manipulate CSS. 133 |
134 | 135 | ") 136 | ``` 137 | 138 | => 139 | => 140 | => Example 141 | => 153 | => 154 | => 155 | =>
156 | =>

Hello #Rstats

157 | =>

A minicss demo!

158 | => This is an example of using minicss to manipulate CSS. 159 | =>
160 | => 161 | => 162 | 163 | 164 | -------------------------------------------------------------------------------- /data-raw/CSSProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "align-content": {"values": ["center", "flex-end", "flex-start", "space-around", "space-between", "stretch"]}, 3 | "align-items": {"values": ["baseline", "center", "flex-end", "flex-start", "stretch"]}, 4 | "align-self": {"values": ["auto", "baseline", "center", "flex-end", "flex-start", "stretch"]}, 5 | "all": {"values": []}, 6 | "animation": {"values": []}, 7 | "animation-delay": {"values": []}, 8 | "animation-direction": {"values": ["alternate", "alternate-reverse", "normal", "reverse"]}, 9 | "animation-duration": {"values": []}, 10 | "animation-fill-mode": {"values": ["backwards", "both", "forwards", "none"]}, 11 | "animation-iteration-count": {"values": ["infinite"]}, 12 | "animation-name": {"values": ["none"]}, 13 | "animation-play-state": {"values": ["paused", "running"]}, 14 | "animation-timing-function": {"values": ["cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "step-end", "step-start", "steps()"]}, 15 | "backface-visibility": {"values": ["hidden", "visible"]}, 16 | "background": {"values": []}, 17 | "background-attachment": {"values": ["fixed", "local", "scroll", "inherit"]}, 18 | "background-blend-mode": {"values": ["color", "color-burn", "color-dodge", "darken", "difference", "exclusion", "hard-light", "hue", "lighten", "luminosity", "multiply", "normal", "overlay", "saturation", "screen", "soft-light"]}, 19 | "background-clip": {"values": ["border-box", "content-box", "padding-box", "inherit"]}, 20 | "background-color": {"values": ["inherit"], "type": "color"}, 21 | "background-image": {"values": ["image()", "linear-gradient()", "radial-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()", "url()"]}, 22 | "background-origin": {"values": ["border-box", "content-box", "padding-box", "inherit"]}, 23 | "background-position": {"values": ["left", "center", "right", "bottom", "top"]}, 24 | "background-repeat": {"values": ["no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space"]}, 25 | "background-size": {"values": ["auto", "contain", "cover"]}, 26 | "border": {"values": []}, 27 | "border-collapse": {"values": ["collapse", "separate", "inherit"]}, 28 | "border-color": {"values": ["inherit"], "type": "color"}, 29 | "border-spacing": {"values": ["inherit"]}, 30 | "border-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 31 | "border-bottom": {"values": []}, 32 | "border-bottom-color": {"values": ["inherit"], "type": "color"}, 33 | "border-bottom-left-radius": {"values": []}, 34 | "border-bottom-right-radius": {"values": []}, 35 | "border-bottom-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 36 | "border-bottom-width": {"values": ["medium", "thin", "thick", "inherit"]}, 37 | "border-image": {"values": [ "url()" ]}, 38 | "border-image-outset": {"values": []}, 39 | "border-image-slice": {"values": []}, 40 | "border-image-source": {"values": []}, 41 | "border-image-repeat": {"values": ["repeat", "round", "space", "stretch"]}, 42 | "border-image-width": {"values": ["auto"]}, 43 | "border-left": {"values": []}, 44 | "border-left-color": {"values": ["inherit"], "type": "color"}, 45 | "border-left-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 46 | "border-left-width": {"values": ["medium", "thin", "thick", "inherit"]}, 47 | "border-radius": {"values": []}, 48 | "border-right": {"values": []}, 49 | "border-right-color": {"values": ["inherit"], "type": "color"}, 50 | "border-right-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 51 | "border-right-width": {"values": ["medium", "thin", "thick", "inherit"]}, 52 | "border-top": {"values": []}, 53 | "border-top-color": {"values": ["inherit"], "type": "color"}, 54 | "border-top-left-radius": {"values": []}, 55 | "border-top-right-radius": {"values": []}, 56 | "border-top-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 57 | "border-top-width": {"values": ["medium", "thin", "thick", "inherit"]}, 58 | "border-width": {"values": ["medium", "thin", "thick", "inherit"]}, 59 | "box-decoration-break": {"values": ["clone", "slice"]}, 60 | "box-shadow": {"values": []}, 61 | "box-sizing": {"values": ["border-box", "content-box", "inherit"]}, 62 | "bottom": {"values": ["auto", "inherit"]}, 63 | "break-after": {"values": ["always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right"]}, 64 | "break-before": {"values": ["always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right"]}, 65 | "break-inside": {"values": ["auto", "avoid", "avoid-column", "avoid-page", "avoid-region"]}, 66 | "caption-side": {"values": ["bottom", "top", "inherit"]}, 67 | "caret-color": {"values": ["auto"], "type": "color"}, 68 | "clear": {"values": ["both", "left", "none", "right", "inherit"]}, 69 | "clip": {"values": ["auto", "inherit"]}, 70 | "color": {"values": ["inherit"], "type": "color"}, 71 | "columns": {"values": []}, 72 | "column-count": {"values": []}, 73 | "column-fill": {"values": ["auto", "balance"]}, 74 | "column-gap": {"values": ["normal"]}, 75 | "column-rule": {"values": []}, 76 | "column-rule-color": {"values": [], "type": "color"}, 77 | "column-rule-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 78 | "column-rule-width": {"values": ["medium", "thin", "thick", "inherit"]}, 79 | "column-span": {"values": ["all", "none"]}, 80 | "column-width": {"values": ["auto", "inherit"]}, 81 | "content": {"values": ["attr()", "close-quote", "no-close-quote", "no-open-quote", "normal", "none", "open-quote", "inherit"]}, 82 | "counter-increment": {"values": ["none", "inherit"]}, 83 | "counter-reset": {"values": ["none", "inherit"]}, 84 | "cursor": {"values": ["alias", "all-scroll", "auto", "cell", "col-resize", "context-menu", "copy", "crosshair", "default", "e-resize", "ew-resize", "grab", "grabbing", "help", "inherit", "move", "n-resize", "ne-resize", "nesw-resize", "no-drop", "none", "not-allowed", "ns-resize", "nw-resize", "nwse-resize", "pointer", "progress", "row-resize", "s-resize", "se-resize", "sw-resize", "text", "vertical-text", "w-resize", "wait", "zoom-in", "zoom-out"]}, 85 | "direction": {"values": ["ltr", "rtl", "inherit"]}, 86 | "display": {"values": ["block", "contents", "flex", "flow-root", "grid", "inline", "inline-block", "inline-flex", "inline-grid", "inline-table", "list-item", "none", "run-in", "subgrid", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "inherit"]}, 87 | "empty-cells": {"values": ["hide", "show", "inherit"]}, 88 | "filter": {"values": ["blur()", "brightness()", "contrast()", "custom()", "drop-shadow()", "grayscale()", "hue-rotate()", "invert()", "none", "opacity()", "sepia()", "saturate()", "url()"]}, 89 | "flex": {"values": ["auto", "initial", "none"]}, 90 | "flex-basis": {"values": ["auto"]}, 91 | "flex-direction": {"values": ["column", "column-reverse", "row", "row-reverse"]}, 92 | "flex-flow": {"values": ["column", "column-reverse", "nowrap", "row", "row-reverse", "wrap", "wrap-reverse"]}, 93 | "flex-grow": {"values": []}, 94 | "flex-shrink": {"values": []}, 95 | "flex-wrap": {"values": ["nowrap", "wrap", "wrap-reverse"]}, 96 | "float": {"values": ["left", "right", "none", "inherit"]}, 97 | "flow-into": {"values": ["none"], "type": "named-flow"}, 98 | "flow-from": {"values": ["none", "inherit"], "type": "named-flow"}, 99 | "font": {"values": []}, 100 | "font-display": {"values": ["auto", "block", "swap", "fallback", "optional"]}, 101 | "font-family": {"values": ["cursive", "fantasy", "inherit", "monospace", "sans-serif", "serif"]}, 102 | "font-feature-settings": {"values": ["normal"]}, 103 | "font-kerning": {"values": ["auto", "none", "normal"]}, 104 | "font-language-override": {"values": ["normal"]}, 105 | "font-size": {"values": []}, 106 | "font-size-adjust": {"values": ["auto", "none"]}, 107 | "font-stretch": {"values": ["condensed", "expanded", "extra-condensed", "extra-expanded", "normal", "semi-condensed", "semi-expanded", "ultra-condensed", "ultra-expanded"]}, 108 | "font-style": {"values": ["italic", "normal", "oblique"]}, 109 | "font-synthesis": {"values": ["none", "style", "weight"]}, 110 | "font-variant": {"values": ["normal", "small-caps", "inherit"]}, 111 | "font-variant-alternates": {"values": ["normal"]}, 112 | "font-variant-caps": {"values": ["normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps"]}, 113 | "font-variant-east-asian": {"values": ["normal"]}, 114 | "font-variant-ligatures": {"values": ["normal", "none"]}, 115 | "font-variant-numeric": {"values": ["normal"]}, 116 | "font-variant-position": {"values": ["normal", "sub", "super"]}, 117 | "font-weight": {"values": ["bold", "bolder", "lighter", "normal", "100", "200", "300", "400", "500", "600", "700", "800", "900", "inherit"]}, 118 | "grid": {"values": []}, 119 | "grid-area": {"values": []}, 120 | "grid-auto-columns": {"values": []}, 121 | "grid-auto-flow": {"values": ["row", "column", "dense"]}, 122 | "grid-auto-rows": {"values": []}, 123 | "grid-column": {"values": ["auto"]}, 124 | "grid-column-end": {"values": []}, 125 | "grid-column-gap": {"values": []}, 126 | "grid-column-start": {"values": []}, 127 | "grid-gap": {"values": []}, 128 | "grid-row": {"values": ["auto"]}, 129 | "grid-row-end": {"values": []}, 130 | "grid-row-start": {"values": []}, 131 | "grid-row-gap": {"values": []}, 132 | "grid-template": {"values": ["none"]}, 133 | "grid-template-areas": {"values": []}, 134 | "grid-template-columns": {"values": ["auto"]}, 135 | "grid-template-rows": {"values": ["auto"]}, 136 | "hanging-punctuation": {"values": ["allow-end", "first", "force-end", "last", "none"]}, 137 | "height": {"values": ["auto", "inherit"]}, 138 | "hyphens": {"values": ["auto", "manual", "none"]}, 139 | "image-orientation": {"values": []}, 140 | "image-resolution": {"values": ["from-image", "snap"]}, 141 | "isolation": {"values": ["auto", "isolate"]}, 142 | "justify-content": {"values": ["center", "flex-end", "flex-start", "space-around", "space-between"]}, 143 | "left": {"values": ["auto", "inherit"]}, 144 | "letter-spacing": {"values": ["normal", "inherit"]}, 145 | "line-height": {"values": ["normal", "inherit"]}, 146 | "list-style": {"values": ["none", "inherit", "initial", "unset", "url()", "armenian", "circle", "decimal", "decimal-leading-zero", "disc", "georgian", "inside", "lower-alpha", "lower-greek", "lower-latin", "lower-roman", "outside", "square", "upper-alpha", "upper-latin", "upper-roman"]}, 147 | "list-style-image": {"values": ["none", "url()", "inherit"]}, 148 | "list-style-position": {"values": ["inside", "outside", "inherit"]}, 149 | "list-style-type": {"values": ["armenian", "circle", "decimal", "decimal-leading-zero", "disc", "georgian", "lower-alpha", "lower-greek", "lower-latin", "lower-roman", "none", "square", "upper-alpha", "upper-latin", "upper-roman", "inherit"]}, 150 | "margin": {"values": ["auto", "inherit"]}, 151 | "margin-bottom": {"values": ["auto", "inherit"]}, 152 | "margin-left": {"values": ["auto", "inherit"]}, 153 | "margin-right": {"values": ["auto", "inherit"]}, 154 | "margin-top": {"values": ["auto", "inherit"]}, 155 | "max-height": {"values": ["none", "inherit"]}, 156 | "max-width": {"values": ["none", "inherit"]}, 157 | "min-height": {"values": ["inherit"]}, 158 | "min-width": {"values": ["inherit"]}, 159 | "mix-blend-mode": {"values": ["color", "color-burn", "color-dodge", "darken", "difference", "exclusion", "hard-light", "hue", "lighten", "luminosity", "multiply", "normal", "overlay", "saturation", "screen", "soft-light"]}, 160 | "object-fit": {"values": ["contain", "cover", "fill", "none", "scale-down"]}, 161 | "object-position": {"values": ["left", "center", "right", "bottom", "top"]}, 162 | "opacity": {"values": ["inherit"]}, 163 | "order": {"values": []}, 164 | "orphans": {"values": ["inherit"]}, 165 | "outline": {"values": ["inherit"]}, 166 | "outline-color": {"values": ["invert", "inherit"], "type": "color"}, 167 | "outline-offset": {"values": ["inherit"]}, 168 | "outline-style": {"values": ["dashed", "dotted", "double", "groove", "hidden", "inset", "none", "outset", "ridge", "solid", "inherit"]}, 169 | "outline-width": {"values": ["medium", "thin", "thick", "inherit"]}, 170 | "overflow": {"values": ["auto", "hidden", "scroll", "visible", "inherit"]}, 171 | "overflow-x": {"values": ["auto", "hidden", "scroll", "visible", "inherit"]}, 172 | "overflow-y": {"values": ["auto", "hidden", "scroll", "visible", "inherit"]}, 173 | "padding": {"values": ["inherit"]}, 174 | "padding-bottom": {"values": []}, 175 | "padding-left": {"values": []}, 176 | "padding-right": {"values": []}, 177 | "padding-top": {"values": []}, 178 | "page-break-after": {"values": ["always", "auto", "avoid", "left", "right", "inherit"]}, 179 | "page-break-before": {"values": ["always", "auto", "avoid", "left", "right", "inherit"]}, 180 | "page-break-inside": {"values": ["auto", "avoid", "inherit"]}, 181 | "perspective": {"values": ["none"]}, 182 | "perspective-origin": {"values": ["bottom", "center", "left", "right", "top"]}, 183 | "pointer-events": {"values": ["all", "auto", "fill", "inherit", "none", "painted", "stroke", "visible", "visibleFill", "visiblePainted", "visibleStroke"]}, 184 | "position": {"values": ["absolute", "fixed", "relative", "static", "sticky", "inherit"]}, 185 | "quotes": {"values": ["none", "inherit"]}, 186 | "region-break-after": {"values": ["always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right"]}, 187 | "region-break-before": {"values": ["always", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "column", "left", "page", "region", "right"]}, 188 | "region-break-inside": {"values": ["auto", "avoid", "avoid-column", "avoid-page", "avoid-region"]}, 189 | "region-fragment": {"values": ["auto", "break"]}, 190 | "resize": {"values": ["both", "horizontal", "none", "vertical", "inherit"]}, 191 | "right": {"values": ["auto", "inherit"]}, 192 | "scroll-behavior": {"values": ["auto", "smooth"]}, 193 | "src": {"values": [ "url()"]}, 194 | "shape-image-threshold": {"values": []}, 195 | "shape-inside": {"values": ["auto", "circle()", "ellipse()", "inherit", "outside-shape", "polygon()", "rectangle()"]}, 196 | "shape-margin": {"values": []}, 197 | "shape-outside": {"values": ["none", "inherit", "circle()", "ellipse()", "polygon()", "inset()", "margin-box", "border-box", "padding-box", "content-box", "url()", "image()", "linear-gradient()", "radial-gradient()", "repeating-linear-gradient()", "repeating-radial-gradient()"]}, 198 | "tab-size": {"values": []}, 199 | "table-layout": {"values": ["auto", "fixed", "inherit"]}, 200 | "text-align": {"values": ["start", "end", "center", "left", "justify", "right", "match-parent", "justify-all", "inherit"]}, 201 | "text-align-last": {"values": ["center", "left", "justify", "right", "inherit"]}, 202 | "text-decoration": {"values": ["line-through", "none", "overline", "underline", "inherit"]}, 203 | "text-decoration-color": {"values": [], "type": "color"}, 204 | "text-decoration-line": {"values": ["line-through", "none", "overline", "underline"]}, 205 | "text-decoration-skip": {"values": ["edges", "ink", "none", "objects", "spaces"]}, 206 | "text-decoration-style": {"values": ["dashed", "dotted", "double", "solid", "wavy"]}, 207 | "text-emphasis": {"values": []}, 208 | "text-emphasis-color": {"values": [], "type": "color"}, 209 | "text-emphasis-position": {"values": ["above", "below", "left", "right"]}, 210 | "text-emphasis-style": {"values": ["circle", "dot", "double-circle", "filled", "none", "open", "sesame", "triangle"]}, 211 | "text-indent": {"values": ["inherit"]}, 212 | "text-justify": {"values": ["auto", "none", "inter-word", "inter-character", "inherit"]}, 213 | "text-overflow": {"values": ["clip", "ellipsis", "inherit"]}, 214 | "text-shadow": {"values": []}, 215 | "text-rendering": {"values": ["auto", "geometricPrecision", "optimizeLegibility", "optimizeSpeed"]}, 216 | "text-transform": {"values": ["capitalize", "full-width", "lowercase", "none", "uppercase", "inherit"]}, 217 | "text-underline-position": {"values": ["alphabetic", "auto", "below", "left", "right"]}, 218 | "top": {"values": ["auto", "inherit"]}, 219 | "transform": {"values": ["matrix()", "matrix3d()", "none", "perspective()", "rotate()", "rotate3d()", "rotateX()", "rotateY()", "rotateZ()", "scale()", "scale3d()", "scaleX()", "scaleY()", "scaleZ()", "skewX()", "skewY()", "translate()", "translate3d()", "translateX()", "translateY()", "translateZ()"]}, 220 | "transform-origin": {"values": ["bottom", "center", "left", "right", "top"]}, 221 | "transform-style": {"values": ["flat", "preserve-3d"]}, 222 | "transition": {"values": []}, 223 | "transition-delay": {"values": []}, 224 | "transition-duration": {"values": []}, 225 | "transition-property": {"values": ["all", "none"]}, 226 | "transition-timing-function": {"values": ["cubic-bezier()", "ease", "ease-in", "ease-in-out", "ease-out", "linear", "step-end", "step-start", "steps()"]}, 227 | "unicode-bidi": {"values": ["bidi-override", "embed", "normal", "inherit"]}, 228 | "unicode-range": {"values": []}, 229 | "user-select": {"values": ["all", "auto", "contain", "none", "text"]}, 230 | "vertical-align": {"values": ["baseline", "bottom", "middle", "sub", "super", "text-bottom", "text-top", "top", "inherit"]}, 231 | "visibility": {"values": ["collapse", "hidden", "visible", "inherit"]}, 232 | "white-space": {"values": ["normal", "nowrap", "pre", "pre-line", "pre-wrap", "inherit"]}, 233 | "widows": {"values": ["inherit"]}, 234 | "width": {"values": ["auto", "inherit"]}, 235 | "will-change": {"values": ["auto", "contents", "opacity", "scroll-position", "transform", "inherit", "initial", "unset"]}, 236 | "word-break": {"values": ["normal", "break-all", "keep-all"]}, 237 | "word-spacing": {"values": ["normal", "inherit"]}, 238 | "word-wrap": {"values": ["break-word", "normal"]}, 239 | "z-index": {"values": ["auto", "inherit"]} 240 | } 241 | -------------------------------------------------------------------------------- /data-raw/property-info.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | library(here) 4 | library(dplyr) 5 | library(jsonlite) 6 | library(purrr) 7 | library(tidyr) 8 | 9 | # JSON source file 10 | # https://github.com/adobe/brackets/blob/master/src/extensions/default/CSSCodeHints/CSSProperties.json 11 | json_file <- here::here("data-raw", "CSSProperties.json") 12 | 13 | json <- jsonlite::read_json(json_file, simplifyVector = TRUE) 14 | 15 | options(useFancyQuotes = FALSE) 16 | 17 | 18 | sink(here::here("R/Css_methods.R")) 19 | 20 | # converting to a 'pretty' list implementation for inclusion in package 21 | # as a source file 22 | cat("css_properties <- list(\n") 23 | for (i in seq_along(json)) { 24 | args <- deparse(json[[i]]$values, width.cutoff = 500) 25 | if (args == 'list()') { 26 | args <- "c()" 27 | } 28 | z <- sprintf(" list(name = %-28s, args = %s)", dQuote(names(json)[i]), args) 29 | if (i == length(json)) { 30 | cat(z, "\n", sep = "") 31 | } else { 32 | cat(z, ",\n", sep = "") 33 | } 34 | } 35 | cat(")\n") 36 | sink() 37 | 38 | -------------------------------------------------------------------------------- /deprecated/css_dec_methods.R: -------------------------------------------------------------------------------- 1 | 2 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | #' Add a helper method to the 'Ruleset' class 4 | #' 5 | #' @param property_name the name of the CSS property. will also be used as the property name 6 | #' @param values character vector of argument names 7 | #' 8 | #' @importFrom glue glue 9 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | add_method <- function(property_name, values) { 11 | 12 | property_name <- gsub("-", "_", property_name) 13 | values <- gsub('-', '_', values) 14 | 15 | if (length(values) == 0) { 16 | arg_text <- "..." 17 | } else { 18 | arg_text <- glue("..., {paste('`', values, '`', sep = '', collapse = ', ')}") 19 | } 20 | 21 | func_text <- glue("function({arg_text}) {{ 22 | res <- as.list(sys.call()) 23 | if (length(res) != 2) stop('${property_name}(): Must have just a single argument') 24 | res <- res[2] 25 | if (is.null(names(res))) {{ 26 | value <- as.character(res) 27 | }} else {{ 28 | value <- names(res) 29 | }} 30 | do.call(self$attr, list({property_name} = value)) 31 | invisible(self) 32 | }}") 33 | 34 | func <- eval(parse(text = func_text)) 35 | 36 | Style$set("public", property_name, func) 37 | func_text 38 | } 39 | 40 | 41 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | # Dynamically add all the element creation methods to 'Style' class 43 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | if (FALSE) { 45 | for (prop in properties) { 46 | add_method(prop$name, prop$values) 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /man/Keyframe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Keyframes.R 3 | \docType{data} 4 | \name{Keyframe} 5 | \alias{Keyframe} 6 | \alias{css_keyframe} 7 | \title{Create a single keyframe for a style at a moment in time.} 8 | \format{An object of class \code{R6ClassGenerator} of length 24.} 9 | \usage{ 10 | Keyframe 11 | } 12 | \description{ 13 | This is identical to the \code{Style} class except the first argument is a 14 | time specification (either 'from', 'to', or a percentage), instead of a name 15 | } 16 | \examples{ 17 | \dontrun{ 18 | Keyframe$new('from', color = '#000000') 19 | Keyframe$new('to' , color = '#ffffff') 20 | } 21 | 22 | } 23 | \keyword{datasets} 24 | -------------------------------------------------------------------------------- /man/Keyframes.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Keyframes.R 3 | \docType{data} 4 | \name{Keyframes} 5 | \alias{Keyframes} 6 | \alias{css_keyframes} 7 | \title{Create a named Keyframes style suitable to insert in a StyleSheet} 8 | \format{An object of class \code{R6ClassGenerator} of length 24.} 9 | \usage{ 10 | Keyframes 11 | } 12 | \description{ 13 | Create a named Keyframes style suitable to insert in a StyleSheet 14 | } 15 | \keyword{datasets} 16 | -------------------------------------------------------------------------------- /man/Selector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Selector.R 3 | \docType{class} 4 | \name{Selector} 5 | \alias{Selector} 6 | \title{CSS selector builder} 7 | \description{ 8 | Based upon a naive reading of \url{https://developer.mozilla.org/en-US/docs/Web/CSS/Reference#Selectors}. 9 | } 10 | \section{Usage}{ 11 | 12 | \preformatted{selector <- Selector$new() 13 | selector <- css_sel() 14 | 15 | selector$type(type_name) 16 | selector$class(...) 17 | selector$id(id_name) 18 | 19 | new_selector <- selector$copy() 20 | 21 | } 22 | } 23 | 24 | \section{Methods}{ 25 | 26 | 27 | \describe{ 28 | 29 | \item{\code{$type(type_name)}}{ 30 | Set the type for the selector 31 | \tabular{ll}{ 32 | \code{type_name} \tab type name \cr 33 | } 34 | } 35 | 36 | \item{\code{$id(id_name)}}{ 37 | Set the id for the selector 38 | \tabular{ll}{ 39 | \code{id_name} \tab id name \cr 40 | } 41 | } 42 | 43 | \item{\code{$class(...)}}{ 44 | Add to the class list for for the selector 45 | \tabular{ll}{ 46 | \code{...} \tab class names \cr 47 | } 48 | } 49 | 50 | \item{\code{$attr(..., modifier = c('exact', 'choice', 'prefix', 'suffix', 'contains'))}}{ 51 | Add attribute matching to the selector. See \url{https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors} 52 | \tabular{ll}{ 53 | \code{...} \tab name/value pairs for the atributes \cr 54 | \code{modifer} \tab by default 'exact' attribute matching, but can select from among the different types of matching \cr 55 | } 56 | } 57 | 58 | \item{\code{$pseudo_class(...)}}{ 59 | Set pseudo classes on the selector. 60 | \tabular{ll}{ 61 | \code{...} \tab Use \code{name = TRUE} to set pseudo-classes \cr 62 | } 63 | } 64 | 65 | \item{\code{$pseudo_element(...)}}{ 66 | Set pseudo element on the selector. 67 | \tabular{ll}{ 68 | \code{...} \tab Use \code{name = TRUE} to set pseudo-elements \cr 69 | } 70 | } 71 | 72 | 73 | 74 | \item{\code{$descendant_of(selector), $parent_of(selector), $child_of(selector), $prior_adjacent(selector), $prior_sibling(selector), $and(selector)}}{ 75 | Set relationship with another selector 76 | \tabular{ll}{ 77 | \code{selector} \tab Other selector \cr 78 | } 79 | } 80 | 81 | \item{\code{$as_character()}}{ 82 | Convert \code{Selector} to a character string. 83 | } 84 | 85 | \item{\code{$print()}}{ 86 | Print \code{Selector} to terminal. 87 | } 88 | 89 | \item{\code{$copy()}}{ 90 | Copy \code{Selector}. 91 | } 92 | 93 | } 94 | } 95 | 96 | \examples{ 97 | \dontrun{ 98 | selector <- css_sel(".marsha")$child_of('carol') 99 | } 100 | 101 | } 102 | \keyword{datasets} 103 | -------------------------------------------------------------------------------- /man/Style.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Style.R 3 | \docType{class} 4 | \name{Style} 5 | \alias{Style} 6 | \title{CSS style builder} 7 | \description{ 8 | CSS style builder 9 | } 10 | \section{Usage}{ 11 | 12 | \preformatted{style <- Style$new() 13 | style <- css_style() 14 | 15 | style$set_selector(".thing") 16 | style$remove("color") 17 | style$update(color = 'blue') 18 | style$as_character() 19 | style$as_inline() 20 | new_style <- style$copy() 21 | 22 | } 23 | } 24 | 25 | \section{Methods}{ 26 | 27 | 28 | \describe{ 29 | 30 | \item{\code{$update(..., selector = NULL)}}{ 31 | Updates the list of properties associated with this style. 32 | \tabular{ll}{ 33 | \code{...} \tab name/value properties \cr 34 | \code{selector} \tab If given, then used as the the selector for this style. If 35 | not given, then the first unnamed argument in \code{...} is interpreted as the 36 | character string for the selector. \cr 37 | } 38 | } 39 | 40 | \item{\code{$set_selector(selector)}}{ 41 | Updates the selector associated with this style. 42 | \tabular{ll}{ 43 | \code{selector} \tab new selector. either a character string or a \code{Selector} object \cr 44 | } 45 | } 46 | 47 | \item{\code{$remove(...)}}{ 48 | Removes properties from this style by name 49 | \tabular{ll}{ 50 | \code{...} \tab names of properties to remove (character strings) \cr 51 | } 52 | } 53 | 54 | \item{\code{$as_character()}}{ 55 | Convert \code{Style} to a character string. 56 | } 57 | 58 | \item{\code{$as_inline()}}{ 59 | Convert \code{Style} to a single character string without the selector, 60 | suitable for use as an inline style. 61 | } 62 | 63 | \item{\code{$print()}}{ 64 | Print \code{Style} to terminal. 65 | } 66 | 67 | \item{\code{$copy()}}{ 68 | Copy \code{Style}. 69 | } 70 | 71 | } 72 | } 73 | 74 | \examples{ 75 | \dontrun{ 76 | css_style('#marsha')$ 77 | update(marsha = 'marsha')$ 78 | update(ptag$display$none, width = "100\%") 79 | } 80 | 81 | } 82 | \keyword{datasets} 83 | -------------------------------------------------------------------------------- /man/StyleSheet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/StyleSheet.R 3 | \docType{class} 4 | \name{StyleSheet} 5 | \alias{StyleSheet} 6 | \alias{css_stylesheet} 7 | \title{CSS style sheet builder} 8 | \description{ 9 | CSS style sheet builder 10 | } 11 | \section{Usage}{ 12 | 13 | \preformatted{sheet <- StyleSheet$new() 14 | sheet <- css_stylesheet() 15 | 16 | sheet$append(style) 17 | sheet$remove(3) 18 | sheet$add('h1', color = 'blue') 19 | sheet$as_character() 20 | new_sheet <- sheet$copy() 21 | 22 | } 23 | } 24 | 25 | \section{Methods}{ 26 | 27 | 28 | \describe{ 29 | 30 | \item{\code{$new(...)}}{ 31 | Initialise a stylesheet 32 | \tabular{ll}{ 33 | \code{...} \tab all arguments treated as \code{Style} objects and added to the style sheet \cr 34 | } 35 | } 36 | 37 | 38 | \item{\code{$append(...)}}{ 39 | Append \code{Style} objects to this StyleSheet 40 | \tabular{ll}{ 41 | \code{...} \tab all arguments treated as Style objects and added to the style sheet \cr 42 | } 43 | } 44 | 45 | \item{\code{$remove(indices)}}{ 46 | Remove \code{Style} objects from this StyleSheet by index. 47 | \tabular{ll}{ 48 | \code{indices} \tab indices of Style objects to remove \cr 49 | } 50 | } 51 | 52 | \item{\code{$add(..., selector = NULL)}}{ 53 | Creates a \code{Style} object and adds it to the StyleSheet. Returns the newly 54 | created \code{Style}. 55 | \tabular{ll}{ 56 | \code{...} \tab name/value properties \cr 57 | \code{selector} \tab If given, then used as the the selector for this style. If 58 | not given, then the first unnamed argument in \code{...} is interpreted as the 59 | character string for the selector. \cr 60 | } 61 | } 62 | 63 | \item{\code{$as_character()}}{ 64 | Convert \code{StyleSheet} to a character string. 65 | } 66 | 67 | \item{\code{$print()}}{ 68 | Print \code{StyleSheet} to terminal. 69 | } 70 | 71 | \item{\code{$copy()}}{ 72 | Copy \code{StyleSheet}. 73 | } 74 | 75 | } 76 | } 77 | 78 | \examples{ 79 | \dontrun{ 80 | marsha <- css_style('#marsha')$ 81 | update(marsha = 'marsha')$ 82 | update(ptag$display$none, width = "100\%") 83 | 84 | sheet <- StyleSheet$new(marsha) 85 | } 86 | 87 | } 88 | \keyword{datasets} 89 | -------------------------------------------------------------------------------- /man/all_named.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{all_named} 4 | \alias{all_named} 5 | \title{Check if all elements are named} 6 | \usage{ 7 | all_named(x) 8 | } 9 | \arguments{ 10 | \item{x}{object e.g. list, vector} 11 | } 12 | \value{ 13 | TRUE if all elements are named, otherwise FALSE 14 | } 15 | \description{ 16 | Check if all elements are named 17 | } 18 | -------------------------------------------------------------------------------- /man/as.character.Selector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Selector.R 3 | \name{as.character.Selector} 4 | \alias{as.character.Selector} 5 | \title{Retrieve the character representation of a Selector object} 6 | \usage{ 7 | \method{as.character}{Selector}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{Selector object} 11 | 12 | \item{...}{other arguments} 13 | } 14 | \description{ 15 | Retrieve the character representation of a Selector object 16 | } 17 | -------------------------------------------------------------------------------- /man/as.character.Style.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Style.R 3 | \name{as.character.Style} 4 | \alias{as.character.Style} 5 | \title{Retrieve the character representation of a Style object} 6 | \usage{ 7 | \method{as.character}{Style}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{Style object} 11 | 12 | \item{...}{other arguments} 13 | } 14 | \description{ 15 | Retrieve the character representation of a Style object 16 | } 17 | -------------------------------------------------------------------------------- /man/as.character.StyleSheet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/StyleSheet.R 3 | \name{as.character.StyleSheet} 4 | \alias{as.character.StyleSheet} 5 | \title{Retrieve the character representation of a SStyleSheettyle object} 6 | \usage{ 7 | \method{as.character}{StyleSheet}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{StyleSheet object} 11 | 12 | \item{...}{other arguments} 13 | } 14 | \description{ 15 | Retrieve the character representation of a SStyleSheettyle object 16 | } 17 | -------------------------------------------------------------------------------- /man/as.character.css_property.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/prop.R 3 | \name{as.character.css_property} 4 | \alias{as.character.css_property} 5 | \title{Convert a CSS 'property' object to a string} 6 | \usage{ 7 | \method{as.character}{css_property}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{property object} 11 | 12 | \item{...}{other arguments} 13 | } 14 | \description{ 15 | Convert a CSS 'property' object to a string 16 | } 17 | -------------------------------------------------------------------------------- /man/css_prop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/prop.R 3 | \docType{data} 4 | \name{css_prop} 5 | \alias{css_prop} 6 | \title{CSS property helper} 7 | \format{An object of class \code{list} of length 238.} 8 | \usage{ 9 | css_prop 10 | } 11 | \description{ 12 | Uses autocomplete to help write some standard propertys 13 | } 14 | \keyword{datasets} 15 | -------------------------------------------------------------------------------- /man/css_sel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Selector.R 3 | \name{css_sel} 4 | \alias{css_sel} 5 | \title{Helper for creating a Selector object} 6 | \usage{ 7 | css_sel(selector = NULL) 8 | } 9 | \arguments{ 10 | \item{selector}{string or another Selector object to clone} 11 | } 12 | \description{ 13 | Helper for creating a Selector object 14 | } 15 | -------------------------------------------------------------------------------- /man/css_style.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Style.R 3 | \name{css_style} 4 | \alias{css_style} 5 | \title{Helper function for creating a Style object for a CSS style (requires selector)} 6 | \usage{ 7 | css_style(..., selector = NULL) 8 | } 9 | \arguments{ 10 | \item{...}{named list of properties for the style e.g. `color = "black"`} 11 | 12 | \item{selector}{character string or object of Selector class} 13 | } 14 | \description{ 15 | Helper function for creating a Style object for a CSS style (requires selector) 16 | } 17 | -------------------------------------------------------------------------------- /man/figures/hello.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/hello.gif -------------------------------------------------------------------------------- /man/figures/inline1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/inline1.png -------------------------------------------------------------------------------- /man/figures/inline2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/inline2.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/logo.png -------------------------------------------------------------------------------- /man/figures/mini-cooper-s.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/mini-cooper-s.gif -------------------------------------------------------------------------------- /man/figures/readme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/readme.gif -------------------------------------------------------------------------------- /man/figures/shiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/man/figures/shiny.png -------------------------------------------------------------------------------- /man/imp.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/prop.R 3 | \name{imp} 4 | \alias{imp} 5 | \title{Helper to manually create new "!important" properies} 6 | \usage{ 7 | imp(...) 8 | } 9 | \arguments{ 10 | \item{...}{a name/value pair} 11 | } 12 | \description{ 13 | Helper to manually create new "!important" properies 14 | } 15 | -------------------------------------------------------------------------------- /man/print.css_property.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/prop.R 3 | \name{print.css_property} 4 | \alias{print.css_property} 5 | \title{Print a CSS 'property' object} 6 | \usage{ 7 | \method{print}{css_property}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{property object} 11 | 12 | \item{...}{other arguments} 13 | } 14 | \description{ 15 | Print a CSS 'property' object 16 | } 17 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolbutuseless/minicss/4289c86fdac18fdfc5bb5ae954ad0ac0cb9aa03a/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/Properties.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Properties" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Properties} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = FALSE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | ``` 20 | 21 | 22 | # CSS Properties 23 | 24 | Property declarations are usually name/value pairs defining the value of a 25 | particular CSS property e.g. `color: #ff0000`. 26 | 27 | Property declarations can be added to styles during intialisation or an update e.g. 28 | 29 | ```{r} 30 | my_style <- Style$new("h1", color = '#ff0000') 31 | my_style$update(margin = '10px') 32 | 33 | my_style 34 | ``` 35 | 36 | 37 | Since there are a few hundred different property names, the `css_prop` helper makes 38 | use of auto-complete to help the user write property declarations. 39 | 40 | ## `css_prop` 41 | 42 | ```{r} 43 | css_prop$`align-content`$center 44 | ``` 45 | 46 | 47 | ```{r} 48 | css_prop$margin$auto 49 | ``` 50 | 51 | 52 | ```{r} 53 | css_prop$color$set('#000') 54 | ``` 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | # More complicated properties 63 | 64 | The `animation` and `transform` properties are a bit more complex and have 65 | entries in `css_prop` which are a more involved. 66 | 67 | 68 | ## Animation declarations 69 | 70 | ```{r} 71 | css_prop$animation(name = 'example', duration = 10, timing_function = 'ease', 72 | iteration_count = 'infinite') 73 | ``` 74 | 75 | 76 | 77 | ## Transform declarations 78 | 79 | Specialized transform helpers exists for all the standard CSS transforms e.g. translate, 80 | rotate, skew etc. 81 | 82 | ```{r} 83 | css_prop$transform$translate(10, 20, unit = '%') 84 | ``` 85 | 86 | -------------------------------------------------------------------------------- /vignettes/Selectors.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Selectors" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Selectors} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | ``` 20 | 21 | 22 | 23 | # CSS Selectors 24 | 25 | Selectors are descriptions of HTML entities on a page. Combined with a list of property/value pairs, they define which elements a particular style applies to. 26 | 27 | Selectors may just be given as a character string, but you can also use the `Selector` 28 | [R6](https://cran.r-project.org/package=R6) class to help build selectors with a 29 | more complex specification. 30 | 31 | 32 | #### CSS Selectors - Example 1 33 | 34 | ```{r} 35 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | # All things with id = 'greg' with class = 'brady' 37 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | myselector <- Selector$new() 39 | myselector$class('brady') 40 | myselector$id('greg') 41 | 42 | myselector 43 | ``` 44 | 45 | 46 | #### CSS Selectors - Example 2 47 | 48 | ```{r} 49 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 | # All 'cindy' IDs which are children of 'carol' classes, and 'bobby' IDs which 51 | # are the last child of 'mike' classes 52 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | parent1 <- css_sel(".carol")$ 54 | parent_of('#cindy') 55 | 56 | parent2 <- css_sel()$ 57 | class('mike')$ 58 | attr(job = 'architect')$ 59 | parent_of( 60 | css_sel()$id('bobby')$pseudo_class(last_child = TRUE) 61 | ) 62 | 63 | parent1$and(parent2) 64 | 65 | parent1 66 | ``` -------------------------------------------------------------------------------- /vignettes/Shiny.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Shiny" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Shiny} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | ``` 20 | 21 | 22 | # Using `minicss` with Shiny 23 | 24 | Style sheets created with `minicss` can be inserted as a style block in the 25 | header of a Shiny UI using `shiny::tags$head` and `shiny::tags$style`. 26 | 27 | Can also use inline styles using `Style$new()` or `css_style` within the creation of 28 | an individual element. 29 | 30 | ```{r eval = FALSE} 31 | # File: app.R 32 | library(minicss) 33 | 34 | # Create a style sheet 35 | my_styles <- css_stylesheet() 36 | my_styles$add('h1', colour = 'white' , background_color = '#123456') 37 | my_styles$add('h2', colour = '#123456', background_color = '#80ff80') 38 | 39 | 40 | ui <- bootstrapPage( 41 | tags$head( 42 | tags$style(my_styles) # set the style sheet for the document 43 | ), 44 | h1("Hello minicss"), 45 | h2("How are you?"), 46 | h3("Hello #RStats", style = css_style(color = 'red')), # inline style 47 | plotOutput('plot') 48 | ) 49 | 50 | server <- function(input, output) { 51 | output$plot <- renderPlot({ 52 | hist(runif(200)) 53 | }) 54 | } 55 | 56 | shinyApp(ui = ui, server = server) 57 | ``` 58 | 59 | 60 | -------------------------------------------------------------------------------- /vignettes/StyleSheets.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "StyleSheets" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{StyleSheets} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = FALSE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | ``` 20 | 21 | 22 | 23 | # CSS Style Sheets 24 | 25 | Style sheets are collections of multiple CSS styles. 26 | 27 | ```{r} 28 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | # Build a single style 30 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | marsha <- css_style('#marsha')$ 32 | update(marsha = 'marsha')$ 33 | update(css_prop$display$none, width = "100%") 34 | 35 | 36 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | # Create a style sheet and add the style to it 38 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | sheet <- StyleSheet$new() 40 | sheet$append(marsha) 41 | 42 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | # Directly create and add a style. 44 | # Note that the 'update' calls are on the style object, not the sheet. 45 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 46 | sheet$add(".greg")$ 47 | update(css_prop$`align-content`$center)$ 48 | update(background = "#123456") 49 | 50 | 51 | sheet 52 | ``` 53 | -------------------------------------------------------------------------------- /vignettes/Styles.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Styles" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Styles} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = FALSE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | library(glue) 20 | ``` 21 | 22 | 23 | # Inline styles 24 | 25 | A style is a collection of property/value pairs (called declarations). 26 | 27 | Use the `prop` helper to auto-complete some common property name/value pairs. 28 | 29 | Use the `imp()` function to create an **!important** property. 30 | 31 | 32 | #### Inline styles - Example 1 33 | 34 | ```{r} 35 | inline_style <- Style$new(color = 'white', background = '#123456') 36 | inline_style 37 | ``` 38 | 39 | ```{r echo = TRUE, eval = FALSE} 40 | glue("
Hello #RStats
") 41 | ``` 42 | 43 | 44 | ```{r echo = FALSE, eval = TRUE} 45 | # Inline styles don't show up on github READMEs 46 | htmltools::HTML(glue("
Hello #RStats
")) 47 | ``` 48 | 49 | 50 | #### Inline styles - Example 2 51 | 52 | Update the pervious style. Use the `prop` helper which uses autocomplete to help 53 | build a standard property/value pair. 54 | 55 | ```{r} 56 | inline_style$ 57 | update(css_prop$`font-family`$monospace)$ 58 | update(width = "25%", imp(color = 'green'), font_size = "25px") 59 | 60 | inline_style 61 | ``` 62 | 63 | 64 | ```{r echo = TRUE, eval = FALSE} 65 | glue("
Hello #RStats
") 66 | ``` 67 | 68 | ```{r echo = FALSE, eval = TRUE} 69 | # Inline styles don't show up on github READMEs 70 | htmltools::HTML(glue("
Hello #RStats
")) 71 | ``` 72 | 73 | 74 | 75 | # CSS Styles 76 | 77 | CSS styles are identical to inline styles, except they must include a *selector* - 78 | this may be either a character string or a `Selector` object. 79 | 80 | The selector can either be defined explicitly with a `selector = "greg"` argument, 81 | of if there is a single unnamed argument, that is assumed to be the selector. 82 | 83 | ```{r} 84 | # Build a selector first 85 | selector <- css_sel(".marsha")$child_of('carol') 86 | 87 | # Build a style using this selector 88 | style <- css_style(selector, colour = 'white')$ 89 | update(css_prop$`text-align`$center) 90 | 91 | style 92 | ``` 93 | 94 | ```{r} 95 | # Or simply use a character string for the selector 96 | (css_style(".greg", colour = 'blue', margin = 'auto')) 97 | ``` 98 | -------------------------------------------------------------------------------- /vignettes/animation.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Animation and Keyframes" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{animation} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = FALSE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ```{r setup} 18 | library(minicss) 19 | library(htmltools) 20 | ``` 21 | 22 | 23 | # Introduction 24 | 25 | Animation using css consists of 26 | 27 | 1. A set of *keyframes* describing the appearance at multiple timepoints 28 | 2. An *animation* declaration (linked to a particular selector) 29 | 30 | ## Simple animation in CSS 31 | 32 | The following CSS code defines 2 keyframes - the first keyframe defines 33 | the colour as red, and the second keyframe defines the colour as green. This 34 | set of keyframes is given the name 'example'. 35 | 36 | The `.ugly` class contains the `animation` declaration which says the animation 37 | should take 1second and should alternate back-and-forth between the two given states 38 | forever (i.e. `infinite` loops) 39 | 40 | ``` 41 | @keyframes example1 { 42 | from { color: #ff0000; } 43 | to { color: #00ff00; } 44 | } 45 | 46 | .ugly { animation: example1 1s infinite alternate; } 47 | ``` 48 | 49 | 50 | ## Create the individual frames with `minicss` 51 | 52 | Create a keyframe by initialising an R6 object of class `Keyframe` 53 | 54 | ```{r} 55 | Keyframe$new(time = 'from', colour = '#000') 56 | ``` 57 | 58 | 59 | Create a keyframe by using the `css_keyframe()` function. 60 | 61 | ```{r} 62 | css_keyframe(time = 'to', colour = '#00f') 63 | ``` 64 | 65 | 66 | Create a keyframe linked to a particular instant in time i.e. 10% through the animation cycle. 67 | 68 | ```{r} 69 | css_keyframe(time = "10%", color = '#123456') 70 | ``` 71 | 72 | 73 | ## Modify a keyframe 74 | 75 | A `Keyframe` object behaves in the same way as `Style` object, individual declarations 76 | can be updated. 77 | 78 | ```{r} 79 | kf <- css_keyframe(time = 'to', colour = '#00f') 80 | kf$update(margin = '10px') 81 | 82 | kf 83 | ``` 84 | 85 | 86 | 87 | 88 | 89 | ## Combine individual keyframes into a `Keyframes` object 90 | 91 | ### Method 1 92 | ```{r} 93 | frame1 <- css_keyframe(time = "from", color = '#123456') 94 | frame2 <- css_keyframe(time = "to" , color = '#0000ff') 95 | 96 | keyframes <- Keyframes$new(name = 'example', frame1, frame2) 97 | keyframes 98 | ``` 99 | 100 | 101 | ### Method 2 102 | 103 | ```{r} 104 | keyframes <- Keyframes$new( 105 | name = 'example', 106 | css_keyframe(time = "from", color = '#123456'), 107 | css_keyframe(time = "to" , color = '#0000ff') 108 | ) 109 | 110 | keyframes 111 | ``` 112 | 113 | ### Method 3 114 | 115 | ```{r} 116 | keyframes <- Keyframes$new(name = 'example') 117 | keyframes$add(time = "from", color = '#123456') 118 | keyframes$add(time = "to" , color = '#0000ff') 119 | 120 | keyframes 121 | ``` 122 | 123 | 124 | ## Create an `animation` declaration 125 | 126 | 127 | This will make use of auto-complete 128 | 129 | ```{r} 130 | css_prop$animation(name = 'example', duration = 2, iteration_count = 3, direction = 'normal') 131 | ``` 132 | 133 | 134 | 135 | 136 | ## Putting it all together 137 | 138 | 139 | ```{r} 140 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 141 | # Construct individual frames 142 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 143 | k1 <- css_keyframe('from', color = '#ffffff') 144 | k2 <- css_keyframe('to' , color = '#123456') 145 | k2$update(css_prop$transform$translateX(40, 'px')) 146 | 147 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148 | # Combine frames into @keyframes 149 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 150 | kf <- css_keyframes('ex1', k1, k2) 151 | 152 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 153 | # Create style to attach @keyframes to the 'h1' type 154 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 155 | my_style <- css_style(".swish", font_size = "50px") 156 | my_style$update( 157 | css_prop$animation('ex1', duration = 1, direction = 'alternate') 158 | ) 159 | 160 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 161 | # Create a style sheet which includes 162 | # - the style for the swish element (including an animation declaration) 163 | # - the keyframes definition 164 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 165 | stylesheet <- css_stylesheet(my_style, kf) 166 | 167 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 168 | # Create a small HTML snippet which uses this style sheet 169 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 170 | html <- glue::glue(" 171 | 172 | 173 | 174 |

Hello #RStats

175 | ") 176 | ``` 177 | 178 | ```{r echo = FALSE} 179 | html 180 | HTML(html) 181 | ``` 182 | 183 | 184 | --------------------------------------------------------------------------------