Skip to content
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
961e696
reacttools: Added R constructor and JS runtime, comments.
alandipert Dec 12, 2018
438ea90
Added sparklines example with README and Windows-compat build
alandipert Dec 13, 2018
0a1ebf3
Add sparklines widget and convert to yarn+webpack-based build
alandipert Dec 14, 2018
b8bb5b9
Initial implementation of resize handling
alandipert Dec 18, 2018
43facab
Improve resize handling
alandipert Dec 19, 2018
42e112e
sparklines example: improve README, make tag a span
alandipert Dec 19, 2018
7fcd97c
Simplify renderOnResize functionality and store entire value instead …
alandipert Dec 19, 2018
70d45a2
Hide the shape of the JSON value send to the client behind new reactD…
alandipert Dec 19, 2018
a519540
Hydrate arbitrary HTML/SVG tags, still throw an exception if a compon…
alandipert Dec 19, 2018
b49a1f4
Remove jQuery dependency from react-tools
alandipert Dec 20, 2018
4f416b0
Add initial impl. of evalJS
alandipert Dec 20, 2018
8738c9b
poc for shiny event handling
timelyportfolio Dec 30, 2018
2d8c765
use shinyEvent instead of shiny and use id prop is available
timelyportfolio Dec 31, 2018
eada87b
Merge pull request #5 from timelyportfolio/enhancements-shiny
timelyportfolio Dec 31, 2018
61095b2
Revert "Merge pull request #5 from timelyportfolio/enhancements-shiny"
timelyportfolio Jan 3, 2019
6c22800
Remove evalJS support until we can think of something better
alandipert Jan 3, 2019
e177aa0
Build fix attempts
alandipert Jan 3, 2019
3855049
Fix reactR::component example
alandipert Jan 3, 2019
657ac05
update version to 0.3.0 and date
timelyportfolio Jan 4, 2019
32a9467
update React and React-DOM to 16.7.0
timelyportfolio Jan 4, 2019
947ea50
change links and references to react-R org
timelyportfolio Jan 4, 2019
f9fba29
Documentation improvements
alandipert Jan 4, 2019
3232e87
Remove examples; moved sparklineswidget to react-R/sparklines
alandipert Jan 4, 2019
9922ad0
Add self as author to DESCRIPTION
alandipert Jan 4, 2019
32b0bea
Added reactR::scaffoldReactWidget for scaffolding output widgets
alandipert Jan 5, 2019
8b39bae
update travis-ci badge to react-R org
timelyportfolio Jan 5, 2019
e955fbc
Merge branch 'enhancements' of https://github.com/react-R/reactR into…
timelyportfolio Jan 5, 2019
184e728
Fix minor bug in scaffold template
alandipert Jan 7, 2019
2b96174
Properly handle text nodes and allow htmltools tags
alandipert Jan 7, 2019
8c26d12
Add example app.R during scaffolding
alandipert Jan 7, 2019
0f4c9e6
use `private: true` to avoid missing maintainer warning
schloerke Jan 7, 2019
305cbc7
Make hydrate more robust and add first JS test
alandipert Jan 7, 2019
5f22d0d
Source map support in test failures
alandipert Jan 8, 2019
b5bf7d7
Attempt Travis matrix build to run JS in addition to R tests
alandipert Jan 8, 2019
1525747
Merge pull request #6 from schloerke/patch-1
alandipert Jan 8, 2019
7b85242
Specify Node version in Travis config
alandipert Jan 8, 2019
2155d4b
Merge branch 'enhancements' of github.com:react-R/reactR into enhance…
alandipert Jan 8, 2019
79ca0d1
Travis: specify R version
alandipert Jan 8, 2019
2305746
Rename reactData => reactMarkup
alandipert Jan 9, 2019
be51515
Rename reactData => reactMarkup
alandipert Jan 9, 2019
eb51153
Use new renderTemplate function for scaffold instead of sprintf
alandipert Jan 9, 2019
c129486
add logo poc
timelyportfolio Jan 10, 2019
434eecb
make img tag markdown
timelyportfolio Jan 10, 2019
7a68a37
remove quotes from img in README
timelyportfolio Jan 10, 2019
1a0e685
specify height of logo in README
timelyportfolio Jan 10, 2019
167779a
use height attribute in logo on README
timelyportfolio Jan 10, 2019
ad8244b
add favicon to docs
timelyportfolio Jan 10, 2019
cb9eea0
move logos to /assets and add to Rbuildignore
timelyportfolio Jan 10, 2019
b40b356
Add more tests
alandipert Jan 10, 2019
1bd4f09
Merge branch 'enhancements' of github.com:react-R/reactR into enhance…
alandipert Jan 10, 2019
2c95b6f
Minor test re-organization
alandipert Jan 10, 2019
2fe2f84
Fix bug in xmlEqual
alandipert Jan 10, 2019
b6d2d24
WIP intro tutorial vignette
alandipert Jan 10, 2019
9b8236e
WIP intro tutorial vignette
alandipert Jan 11, 2019
300823c
Add 4th reactWidget arg to JS template
alandipert Jan 11, 2019
1812397
Further expand htmlwidget intro vignette
alandipert Jan 11, 2019
0102c8f
Complete tutorial
alandipert Jan 11, 2019
aa0c195
Ignore JS stuff in .Rbuildignore
alandipert Jan 11, 2019
9cc3310
Add corejs dependency to scaffold so widgets work in RStudio <1.2
alandipert Jan 11, 2019
af330c9
Improve R docs
alandipert Jan 11, 2019
5a80783
reactMarkup: error if tag isn't shiny.tag or string
alandipert Jan 11, 2019
68c1f4d
Handle primitive strings as top-level elements in JavaScript
alandipert Jan 11, 2019
c37c588
Document defaultOptions
alandipert Jan 11, 2019
ab9a66d
Ignore R CMD check related things in dir
alandipert Jan 11, 2019
ca7b313
Fix typo in tutorial
alandipert Jan 11, 2019
c31d721
Minor tutorial improvement
alandipert Jan 11, 2019
e0f62a6
Small enhancements suggested by @cpsievert
alandipert Jan 11, 2019
1808e9d
reactMarkup: return list with class reactR_markup instead of reactR.m…
alandipert Jan 11, 2019
ad28dc9
Various documentation additions, enhancements
alandipert Jan 11, 2019
9983058
Make vignette more geared towards an R user that wants to quickly lea…
cpsievert Jan 12, 2019
582bb4a
update date and add mention of htmlwdiget in DESCRIPTION
timelyportfolio Jan 12, 2019
8174f4d
add some discussion on new htmlwidget functionality in README
timelyportfolio Jan 12, 2019
9e94c1a
add htmltools:: to taglist in _html function in R template
timelyportfolio Jan 12, 2019
5c2e639
Merge branch 'enhancements' into htmlwidgets-vignette
alandipert Jan 12, 2019
9659531
Merge pull request #7 from cpsievert/htmlwidgets-vignette
alandipert Jan 12, 2019
a513900
Fix intro vignette frontmatter syntax
alandipert Jan 12, 2019
f5fff43
npmPkg: Use a named list instead of a char vector
alandipert Jan 12, 2019
e66b71d
Tutorial vignette: light editing and formatting
alandipert Jan 12, 2019
e519b6d
Minor README edits
alandipert Jan 12, 2019
ed5b725
Remove QA note from tutorial vignette
alandipert Jan 12, 2019
b7f83dd
Minor vignette edit
alandipert Jan 12, 2019
25a2d9c
spark-lines => react-sparklines
alandipert Jan 12, 2019
02cac39
Credit @cpsievert in tutorial
alandipert Jan 12, 2019
c439aa9
pkgdown
timelyportfolio Jan 12, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
^node_modules$
^.*\.Rproj$
^\.Rproj\.user$
^\build
^CONDUCT\.md$
^cran-comments\.md$
^docs$
^\.travis\.yml$
^\assets
^karma\.conf\.js$
^package\.json$
^yarn\.lock$
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
.RData
.Ruserdata
inst/doc
node_modules
reactR.Rcheck
reactR_*.tar.gz
23 changes: 15 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# R for travis: see documentation at https://docs.travis-ci.com/user/languages/r

language: R
sudo: required
cache: packages

before_install:
- sudo apt-get install -y libv8-dev
matrix:
include:
# R for travis: see documentation at https://docs.travis-ci.com/user/languages/r
- language: r
r:
- release
sudo: required
cache: packages
before_install:
- sudo apt-get install -y libv8-dev
- language: node_js
node_js:
- "11.4.0"
addons:
- chrome: stable
17 changes: 12 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: reactR
Type: Package
Title: React Helpers
Version: 0.2.1
Date: 2018-10-23
Version: 0.3.0
Date: 2019-01-03
Authors@R: c(
person(
"Facebook", "Inc"
Expand All @@ -14,16 +14,23 @@ Authors@R: c(
, role = c("aut", "cre")
, comment = "R interface"
, email = "[email protected]"
),
person(
"Alan", "Dipert"
, role = c("aut")
, comment = "R interface"
, email = "[email protected]"
)
)
Maintainer: Kent Russell <[email protected]>
Description: Make it easy to use 'React' in R with helper
dependency functions, embedded 'Babel' 'transpiler',
and examples.
URL: https://github.com/timelyportfolio/reactR
BugReports: https://github.com/timelyportfolio/reactR/issues
URL: https://github.com/react-R/reactR
BugReports: https://github.com/react-R/reactR/issues
License: MIT + file LICENSE
LazyData: TRUE
Encoding: UTF-8
Imports:
htmltools
Suggests:
Expand All @@ -32,5 +39,5 @@ Suggests:
shiny,
V8,
knitr
RoxygenNote: 6.0.1
RoxygenNote: 6.1.1
VignetteBuilder: knitr
9 changes: 9 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Generated by roxygen2: do not edit by hand

S3method("$",react_component_builder)
S3method("$<-",react_component_builder)
S3method("[[",react_component_builder)
S3method("[[<-",react_component_builder)
export(React)
export(babel_transform)
export(component)
export(html_dependency_corejs)
export(html_dependency_react)
export(html_dependency_reacttools)
export(reactMarkup)
export(scaffoldReactWidget)
importFrom(htmltools,htmlDependency)
16 changes: 16 additions & 0 deletions R/dependencies.R
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,19 @@ html_dependency_corejs <- function() {
script = "shim.min.js"
)
}

#' Adds window.reactR.exposeComponents and window.reactR.hydrate
#'
#' @return
#' @export
#'
#' @examples
html_dependency_reacttools <- function(){
htmltools::htmlDependency(
name = "reactwidget",
src = "www/react-tools",
version = "1.0.0",
package = "reactR",
script = c("react-tools.js")
)
}
2 changes: 1 addition & 1 deletion R/meta.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#'@keywords internal
react_version <- function(){'16.6.0'}
react_version <- function(){'16.7.0'}
babel_version <- function(){'6.26.0'}
91 changes: 91 additions & 0 deletions R/reacttools.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
isUpper <- function(s) {
grepl("^[[:upper:]]+$", s)
}

#' Create a React component
#'
#' @param name Name of the React component, which must start with an upper-case
#' character.
#' @param varArgs Attributes and children of the element to pass along to
#' \code{\link[htmltools]{tag}} as \code{varArgs}.
#'
#' @return An htmltools \code{\link[htmltools]{tag}} object
#' @export
#'
#' @examples
#' component("ParentComponent",
#' list(
#' x = 1,
#' y = 2,
#' component("ChildComponent"),
#' component("OtherChildComponent")
#' )
#' )
component <- function(name, varArgs = list()) {
if (length(name) == 0 || !isUpper(substring(name, 1, 1))) {
stop("Component name must be specified and start with an upper case character")
}
htmltools::tag(name, varArgs)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to add a class or a subclass here? As a package author, I might want to know if a user is supplying a component versus a tag


#' React component builder.
#'
#' \code{React} is a syntactically-convenient way to create instances of React
#' components that can be sent to the browser for display. It is a list for
#' which \link[=InternalMethods]{extract methods} are defined, allowing
#' object creation syntax like \code{React$MyComponent(x = 1)} where
#' \code{MyComponent} is a React component you have exposed to Shiny in
#' JavaScript.
#'
#' Internally, the \code{\link{component}} function is used to create the
#' component instance.
#'
#' @examples
#' # Create an instance of ParentComponent with two children,
#' # ChildComponent and OtherChildComponent.
#' React$ParentComponent(
#' x = 1,
#' y = 2,
#' React$ChildComponent(),
#' React$OtherChildComponent()
#' )
#' @export
React <- structure(
list(),
class = "react_component_builder"
)

#' @export
`$.react_component_builder` <- function(x, name) {
function(...) {
component(name, list(...))
}
}

#' @export
`[[.react_component_builder` <- `$.react_component_builder`

#' @export
`$<-.react_component_builder` <- function(x, name, value) {
stop("Assigning to a component constructor is not allowed")
}

#' @export
`[[<-.react_component_builder` <- `$<-.react_component_builder`

#' Prepare data that represents a single-element character vector, a React
#' component, or an htmltools tag for sending to the client.
#'
#' @param tag character vector or React component or
#' \code{\link[htmltools]{tag}}
#'
#' @return
#' @export
#'
#' @examples
reactMarkup <- function(tag) {
stopifnot(class(tag) == "shiny.tag"
|| (is.character(tag) && length(tag) == 1))
list(tag = tag, class = "reactR.markup")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inherits(tag, "shiny.tag") seems more appropriate here. Also, what about "shiny.tag.list"? Perhaps you could allow a lit then wrap it in a div?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point about tag lists. There's actually an analogous React thing we could support that they could turn into, React.Fragment. But I think we should maybe add that in a future PR.

}

157 changes: 157 additions & 0 deletions R/scaffold.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#' Create implementation scaffolding for a React.js-based HTML widget
#'
#' Add the minimal code required to implement a React.js-based HTML widget to an
#' R package.
#'
#' @param name Name of widget
#' @param npmPkg Optional \href{https://npmjs.com/}{NPM} package upon which this
#' widget is based, as a two-element character vector of name and
#' \href{https://docs.npmjs.com/files/package.json#dependencies}{version
#' range}. If you specify this parameter the package will be added to the
#' \code{dependency} section of the generated \code{package.json}.
#' @param edit Automatically open the widget's JavaScript source file after
#' creating the scaffolding.
#'
#' @note This function must be executed from the root directory of the package
#' you wish to add the widget to.
#'
#' @export
scaffoldReactWidget <- function(name, npmPkg = NULL, edit = interactive()){
if (!file.exists('DESCRIPTION')){
stop(
"You need to create a package to house your widget first!",
call. = F
)
}
if (!file.exists('inst')){
dir.create('inst')
}
package <- read.dcf('DESCRIPTION')[[1,"Package"]]
addWidgetConstructor(name, package, edit)
addWidgetYAML(name, edit)
addPackageJSON(toDepJSON(npmPkg))
addWebpackConfig(name)
addWidgetJS(name, edit)
addExampleApp(name)
message("To install dependencies from npm run: yarn install")
message("To build JavaScript run: yarn run webpack --mode=development")
}

toDepJSON <- function(npmPkg) {
if (is.null(npmPkg)) {
""
} else {
do.call(sprintf, as.list(c('"%s": "%s"', npmPkg)))
}
}

slurp <- function(file) {
paste(readLines(
system.file(file, package = 'reactR')
), collapse = "\n")
}

# Perform a series of pattern replacements on str.
# Example: renderTemplate("foo ${x} bar ${y} baz ${x}", list(x = 1, y = 2))
# Produces: "foo 1 bar 2 baz 1"
renderTemplate <- function(str, substitutions) {
Reduce(function(str, name) {
gsub(paste0("\\$\\{", name, "\\}"), substitutions[[name]], str)
}, names(substitutions), str)
}

capName = function(name){
paste0(toupper(substring(name, 1, 1)), substring(name, 2))
}

addWidgetConstructor <- function(name, package, edit){
tpl <- slurp('templates/widget_r.txt')
if (!file.exists(file_ <- sprintf("R/%s.R", name))){
cat(
renderTemplate(tpl, list(name = name, package = package, capName = capName(name))),
file = file_
)
message('Created boilerplate for widget constructor ', file_)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}

addWidgetYAML <- function(name, edit){
tpl <- "# (uncomment to add a dependency)
# dependencies:
# - name:
# version:
# src:
# script:
# stylesheet:
"
if (!file.exists('inst/htmlwidgets')){
dir.create('inst/htmlwidgets')
}
if (!file.exists(file_ <- sprintf('inst/htmlwidgets/%s.yaml', name))){
cat(tpl, file = file_)
message('Created boilerplate for widget dependencies at ',
sprintf('inst/htmlwidgets/%s.yaml', name)
)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}

addPackageJSON <- function(npmPkg) {
tpl <- renderTemplate(slurp('templates/widget_package.json.txt'), list(npmPkg = npmPkg))
if (!file.exists('package.json')) {
cat(tpl, file = 'package.json')
message('Created package.json')
} else {
message("package.json already exists")
}
}

addWebpackConfig <- function(name) {
tpl <- renderTemplate(slurp('templates/widget_webpack.config.js.txt'), list(name = name))
if (!file.exists('webpack.config.js')) {
cat(tpl, file = 'webpack.config.js')
message('Created webpack.config.js')
} else {
message("webpack.config.js already exists")
}
}

addWidgetJS <- function(name, edit){
tpl <- paste(readLines(
system.file('templates/widget_js.txt', package = 'reactR')
), collapse = "\n")
if (!file.exists('srcjs')){
dir.create('srcjs')
}
if (!file.exists(file_ <- sprintf('srcjs/%s.js', name))){
cat(renderTemplate(tpl, list(name = name)), file = file_)
message('Created boilerplate for widget javascript bindings at ',
sprintf('srcjs/%s.js', name)
)
} else {
message(file_, " already exists")
}
if (edit) fileEdit(file_)
}

addExampleApp <- function(name) {
tpl <- renderTemplate(slurp('templates/widget_app.R.txt'), list(name = name, capName = capName(name)))
if (!file.exists('app.R')) {
cat(tpl, file = 'app.R')
message('Created example app.R')
} else {
message("app.R already exists")
}
}

# invoke file.edit in a way that will bind to the RStudio editor
# when running inside RStudio
fileEdit <- function(file) {
fileEditFunc <- eval(parse(text = "file.edit"), envir = globalenv())
fileEditFunc(file)
}
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/reactR)](https://cran.r-project.org/package=reactR)
[![Travis-CI Build Status](https://travis-ci.org/timelyportfolio/reactR.svg?branch=master)](https://travis-ci.org/timelyportfolio/reactR)
[![Travis-CI Build Status](https://travis-ci.org/react-R/reactR.svg?branch=master)](https://travis-ci.org/react-R/reactR)

<img height="150px" alt="react-R logo" src="assets/logos/reactR-logo.png"/>

# reactR

Expand All @@ -11,7 +13,7 @@ You can install reactR from github with:

```R
# install.packages("devtools")
devtools::install_github("timelyportfolio/reactR")
devtools::install_github("react-R/reactR")
```

## Example
Expand Down
Loading