├── .Rbuildignore ├── .gitattributes ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── CONDUCT.md ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── babel.R ├── dependencies.R ├── meta.R ├── reacttools.R ├── scaffold_input.R ├── scaffold_utils.R └── scaffold_widget.R ├── README.Rmd ├── README.md ├── assets └── logos │ ├── reactR-logo-inkscape.svg │ ├── reactR-logo.png │ └── reactR-logo.svg ├── buildupdate └── getreact.R ├── cran-comments.md ├── docs ├── 404.html ├── CONDUCT.html ├── LICENSE-text.html ├── 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 ├── articles │ ├── index.html │ ├── input_app.jpg │ ├── input_sketchpicker.jpg │ ├── input_sketchpicker.mp4 │ ├── intro_htmlwidgets.html │ ├── intro_htmlwidgets_files │ │ └── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ ├── intro_inputs.html │ ├── intro_inputs_files │ │ └── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ ├── intro_reactR.html │ ├── intro_reactR_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ ├── react-16.12.0 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ │ ├── react-16.7.0 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ │ ├── react-16.8.1 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ │ ├── react-16.8.6 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ │ ├── react-17.0.0 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ │ └── react-18.2.0 │ │ │ ├── AUTHORS │ │ │ ├── LICENSE.txt │ │ │ ├── react-dom.min.js │ │ │ └── react.min.js │ ├── logo.svg │ ├── widget_app.jpg │ └── widget_app_improved.jpg ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── docsearch.css ├── docsearch.js ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── React.html │ ├── Rplot001.png │ ├── babel_transform.html │ ├── component.html │ ├── createReactShinyInput.html │ ├── html_dependency_corejs.html │ ├── html_dependency_mobx.html │ ├── html_dependency_react.html │ ├── html_dependency_reacttools.html │ ├── index.html │ ├── reactMarkup.html │ ├── scaffoldReactShinyInput.html │ └── scaffoldReactWidget.html └── sitemap.xml ├── inst ├── examples │ ├── antd.R │ └── office-fabric.R ├── templates │ ├── input_app.R.txt │ ├── input_js.txt │ ├── input_r.txt │ ├── package.json.txt │ ├── webpack.config.js.txt │ ├── widget_app.R.txt │ ├── widget_js.txt │ ├── widget_r.txt │ └── widget_yaml.txt └── www │ ├── babel │ └── babel.min.js │ ├── core-js │ ├── LICENSE │ ├── package.json │ └── shim.min.js │ ├── mobx │ ├── LICENSE │ ├── mobx-react-lite.js │ ├── mobx-react.umd.js │ ├── mobx.min.js │ ├── mobx.umd.min.js │ └── package.json │ ├── react-tools │ └── react-tools.js │ └── react │ ├── AUTHORS │ ├── LICENSE.txt │ ├── react-dom.min.js │ └── react.min.js ├── js-tests └── react-tools.test.jsx ├── man ├── React.Rd ├── babel_transform.Rd ├── component.Rd ├── createReactShinyInput.Rd ├── html_dependency_corejs.Rd ├── html_dependency_mobx.Rd ├── html_dependency_react.Rd ├── html_dependency_reacttools.Rd ├── reactMarkup.Rd ├── scaffoldReactShinyInput.Rd └── scaffoldReactWidget.Rd ├── package-lock.json ├── package.json ├── 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 ├── reactR.Rproj ├── srcjs ├── input.js ├── react-tools.js └── widget.js ├── vignettes ├── input_app.jpg ├── input_sketchpicker.jpg ├── input_sketchpicker.mp4 ├── intro_htmlwidgets.Rmd ├── intro_inputs.Rmd ├── intro_reactR.Rmd ├── logo.svg ├── widget_app.jpg └── widget_app_improved.jpg └── vite.config.js /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^CRAN-RELEASE$ 2 | ^node_modules$ 3 | ^js-tests$ 4 | ^srcjs$ 5 | ^pkgdown$ 6 | ^assets$ 7 | ^.*\.Rproj$ 8 | ^CONDUCT\.md$ 9 | ^README\.Rmd$ 10 | ^\.Rproj\.user$ 11 | ^buildupdate$ 12 | ^docs$ 13 | ^cran-comments\.md$ 14 | ^logo.svg$ 15 | ^package\.json$ 16 | ^vite\.config\.js$ 17 | ^package-lock\.json$ 18 | ^logo\.svg$ 19 | ^\.github$ 20 | ^CRAN-SUBMISSION$ 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /inst/www/react-tools/react-tools.js binary 2 | /inst/www/react-tools/react-tools.js.map binary 3 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Meta 2 | doc 3 | .Rproj.user 4 | .Rhistory 5 | .RData 6 | .Ruserdata 7 | inst/doc 8 | node_modules 9 | reactR.Rcheck 10 | reactR_*.tar.gz 11 | *.swp 12 | .DS_Store 13 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (http:contributor-covenant.org), version 1.0.0, available at 25 | http://contributor-covenant.org/version/1/0/0/ 26 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: reactR 2 | Type: Package 3 | Title: React Helpers 4 | Version: 0.6.1 5 | Date: 2024-09-14 6 | Authors@R: c( 7 | person( 8 | "Facebook", "Inc" 9 | , role = c("aut", "cph") 10 | , comment = "React library in lib, https://reactjs.org/; see AUTHORS for full list of contributors" 11 | ), 12 | person( 13 | "Michel","Weststrate", 14 | , role = c("aut", "cph") 15 | , comment = "mobx library in lib, https://github.com/mobxjs" 16 | ), 17 | person( 18 | "Kent", "Russell" 19 | , role = c("aut", "cre") 20 | , comment = "R interface" 21 | , email = "kent.russell@timelyportfolio.com" 22 | ), 23 | person( 24 | "Alan", "Dipert" 25 | , role = c("aut") 26 | , comment = "R interface" 27 | , email = "alan@rstudio.com" 28 | ), 29 | person( 30 | "Greg", "Lin" 31 | , role = c("aut") 32 | , comment = "R interface" 33 | , email = "glin@glin.io" 34 | ) 35 | ) 36 | Maintainer: Kent Russell 37 | Description: Make it easy to use 'React' in R with 'htmlwidget' scaffolds, 38 | helper dependency functions, an embedded 'Babel' 'transpiler', 39 | and examples. 40 | URL: https://github.com/react-R/reactR 41 | BugReports: https://github.com/react-R/reactR/issues 42 | License: MIT + file LICENSE 43 | LazyData: TRUE 44 | Encoding: UTF-8 45 | Imports: 46 | htmltools 47 | Suggests: 48 | htmlwidgets (>= 1.5.3), 49 | rmarkdown, 50 | shiny, 51 | V8, 52 | knitr, 53 | usethis, 54 | jsonlite 55 | RoxygenNote: 7.3.2 56 | VignetteBuilder: knitr 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2018 2 | COPYRIGHT HOLDER: Kent Russell 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method("$",react_component_builder) 4 | S3method("$<-",react_component_builder) 5 | S3method("[[",react_component_builder) 6 | S3method("[[<-",react_component_builder) 7 | export(React) 8 | export(babel_transform) 9 | export(component) 10 | export(createReactShinyInput) 11 | export(html_dependency_corejs) 12 | export(html_dependency_mobx) 13 | export(html_dependency_react) 14 | export(html_dependency_reacttools) 15 | export(reactMarkup) 16 | export(scaffoldReactShinyInput) 17 | export(scaffoldReactWidget) 18 | importFrom(htmltools,htmlDependency) 19 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # reactR 0.6.1 2 | 3 | * Fix issue where the `react-tools.umd.cjs` script could be blocked by the browser in some cases, such as apps deployed on shinyapps.io [#86](https://github.com/react-R/reactR/issues/86) 4 | 5 | # reactR 0.6.0 6 | 7 | * retain `list` in `reactR::component` classes [#82](https://github.com/react-R/reactR/issues/82) 8 | * hydrate props/attribs that are tags assuming tag-like props/attribs should be slots[#67](https://github.com/react-R/reactR/issues/67) [#61](https://github.com/react-R/reactR/issues/61) 9 | * update build tools to `vite` from `webpack` 10 | * update js testing library from `karma` to `vitest` 11 | 12 | 13 | # reactR 0.5.0 14 | 15 | * Update react to `18.2.0` 16 | 17 | # reactR 0.4.4 18 | 19 | * Update react to `16.12.0` 20 | 21 | * Add `style-loader` and `css-loader` to webpack config [pull 50](https://github.com/react-R/reactR/pull/50) 22 | 23 | * Update to `PACKAGE::widget_html.WIDGETNAME` for new `htmlwidgets` convention [pull 49](https://github.com/react-R/reactR/pull/49) 24 | 25 | * Clean up template [pull 45](https://github.com/react-R/reactR/pull/45) 26 | 27 | # reactR 0.4.3 28 | 29 | * Add element to Shiny input [pull 41](https://github.com/react-R/reactR/pull/41) 30 | 31 | * Upgrade npm dependencies 32 | 33 | # reactR 0.4.2 34 | 35 | * Update react to `16.12.0` 36 | 37 | * Update core-js to `2.6.11` 38 | 39 | # reactR 0.4.1 40 | 41 | * Add support for `shiny::registerInputHandler` in Shiny inputs; [pull 28](https://github.com/react-R/reactR/pull/28) 42 | 43 | * Add support for Shiny rate limit [pull 29](https://github.com/react-R/reactR/pull/29) 44 | 45 | * Update react to `16.8.6` 46 | 47 | * Add `mobx` dependencies available through `html_dependency_mobx()` 48 | 49 | # reactR 0.4.0 50 | 51 | * Add Shiny input scaffold and functionality; [tutorial](https://react-r.github.io/reactR/articles/intro_inputs.html) and [pull 22](https://github.com/react-R/reactR/pull/22) thanks @alandipert 52 | 53 | # reactR 0.3.1 54 | 55 | * Update react and react-dom to 16.8.1 56 | * Add `usethis` R dependency 57 | * Ignore node_modules in `.Rbuildignore` and `.gitignore` 58 | * Set `{modules:false}` in `babel_transform` to avoid `"use strict"`; [pull 15](https://github.com/react-R/reactR/pull/15) 59 | * Use webpack to build `react-tools.js`; [pull 16](https://github.com/react-R/reactR/pull/16) 60 | * Attach component to the htmlwidget 61 | 62 | # reactR 0.3.0 63 | 64 | * Add htmlwidget scaffold and helpers (see [tutorial](https://react-r.github.io/reactR/articles/intro_htmlwidgets.html)) 65 | * Update react and react-dom to 16.6.7 66 | 67 | # reactR 0.2.1 68 | 69 | * Update react and react-dom to 16.6.0 70 | 71 | # reactR 0.2.0 72 | 73 | * Update react and react-dom to 16.2.0 74 | * Add core-js shim so that React will show up in RStudio Viewer 75 | 76 | # reactR 0.1.4 77 | 78 | * Update react and react-dom to 16.1.1 79 | 80 | # reactR 0.1.3 81 | 82 | * Update react and react-dom to 16.0.0 83 | * Update babel to 6.26.0 84 | 85 | # reactR 0.1.2 86 | 87 | * Update to react `15.5.0` 88 | * Update to babel `6.24.0` 89 | * Add fluent-ui(fabric) example 90 | * Build doc site with `pkgdown` 91 | 92 | # reactR 0.1.1 93 | 94 | * Added a `NEWS.md` file to track changes to the package. 95 | * Provide offline babel-standalone for babel_transform 96 | 97 | # reactR 0.1.0 98 | 99 | * Initial release 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /R/babel.R: -------------------------------------------------------------------------------- 1 | #' Transform Code with Babel 2 | #' 3 | #' Helper function to use \code{V8} with \code{Babel} so we can 4 | #' avoid a JSX transformer with using \code{reactR}. 5 | #' 6 | #' @param code \code{character} 7 | #' 8 | #' @return transformed \code{character} 9 | #' @export 10 | #' 11 | #' @examples 12 | #' \dontrun{ 13 | #' library(reactR) 14 | #' babel_transform('
react div
') 15 | #' } 16 | babel_transform <- function(code=""){ 17 | stopifnot(requireNamespace("V8"), is.character(code)) 18 | 19 | ctx <- V8::v8() 20 | ctx$source( 21 | system.file( 22 | "www/babel/babel.min.js", 23 | package = "reactR" 24 | ) 25 | ) 26 | ctx$assign('code', code) 27 | ctx$get('Babel.transform(code,{ presets: [["es2015", {modules: false}],"react"] }).code') 28 | } 29 | -------------------------------------------------------------------------------- /R/dependencies.R: -------------------------------------------------------------------------------- 1 | #' Dependencies for React 2 | #' 3 | #' Add JavaScript 'React' dependency. For this to work in RStudio Viewer, also include 4 | #' \code{\link{html_dependency_corejs}}. 5 | #' 6 | #' @param offline \code{logical} to use local file dependencies. If \code{FALSE}, 7 | #' then the dependencies use the Facebook cdn as its \code{src}. 8 | #' To use with \code{JSX} see \code{\link{babel_transform}}. 9 | #' 10 | #' @return \code{\link[htmltools]{htmlDependency}} 11 | #' @importFrom htmltools htmlDependency 12 | #' @export 13 | #' 14 | #' @examples 15 | #' library(reactR) 16 | #' library(htmltools) 17 | #' 18 | #' tagList( 19 | #' tags$script( 20 | #' " 21 | #' ReactDOM.render( 22 | #' React.createElement( 23 | #' 'h1', 24 | #' null, 25 | #' 'Powered by React' 26 | #' ), 27 | #' document.body 28 | #' ) 29 | #' " 30 | #' ), 31 | #' #add core-js first to work in RStudio Viewer 32 | #' html_dependency_corejs(), 33 | #' html_dependency_react() #offline=FALSE for CDN 34 | #' ) 35 | html_dependency_react <- function(offline=TRUE){ 36 | hd <- htmltools::htmlDependency( 37 | name = "react", 38 | version = react_version(), 39 | src = system.file("www/react",package="reactR"), 40 | script = c("react.min.js", "react-dom.min.js") 41 | ) 42 | 43 | if(!offline) { 44 | hd$src <- list(href="//unpkg.com") 45 | 46 | hd$script <- c( 47 | "react/umd/react.production.min.js", 48 | "react-dom/umd/react-dom.production.min.js" 49 | ) 50 | } 51 | 52 | hd 53 | } 54 | 55 | 56 | #' Shim Dependency for React in RStudio Viewer 57 | #' 58 | #' Add this first for 'React' to work in RStudio Viewer. 59 | #' 60 | #' @return \code{\link[htmltools]{htmlDependency}} 61 | #' @importFrom htmltools htmlDependency 62 | #' @export 63 | html_dependency_corejs <- function() { 64 | #shim/polyfill for ES5 and ES6 so react will show up in RStudio Viewer 65 | #https://unpkg.com/core-js@2.5.3/ 66 | htmltools::htmlDependency( 67 | name = "core-js", 68 | version = "2.5.3", 69 | src = c(file=system.file("www/core-js/", package="reactR")), 70 | script = "shim.min.js" 71 | ) 72 | } 73 | 74 | #' Adds window.reactR.exposeComponents and window.reactR.hydrate 75 | #' 76 | #' @return \code{\link[htmltools]{htmlDependency}} 77 | #' @importFrom htmltools htmlDependency 78 | #' @export 79 | html_dependency_reacttools <- function(){ 80 | htmltools::htmlDependency( 81 | name = "reactwidget", 82 | src = "www/react-tools", 83 | version = "2.0.0", 84 | package = "reactR", 85 | script = c("react-tools.js") 86 | ) 87 | } 88 | 89 | #' Dependencies for 'mobx' 90 | #' 91 | #' Add JavaScript 'mobx' and 'mobx-react' dependency. When using with 'react', the order 92 | #' of the dependencies is important, so please add \code{html_dependency_react()} before 93 | #' \code{html_dependency_mobx()}. 94 | #' 95 | #' @param react \code{logical} to add react 'mobx' dependencies. 96 | #' 97 | #' @return \code{\link[htmltools]{htmlDependency}} 98 | #' @importFrom htmltools htmlDependency 99 | #' @export 100 | #' 101 | #' @examples 102 | #' if(interactive()) { 103 | #' 104 | #' library(htmltools) 105 | #' library(reactR) 106 | #' 107 | #' browsable( 108 | #' tagList( 109 | #' html_dependency_mobx(react = FALSE), 110 | #' div(id="test"), 111 | #' tags$script(HTML( 112 | #' " 113 | #' var obs = mobx.observable({val: null}) 114 | #' mobx.autorun(function() { 115 | #' document.querySelector('#test').innerText = obs.val 116 | #' }) 117 | #' setInterval( 118 | #' function() {obs.val++}, 119 | #' 1000 120 | #' ) 121 | #' " 122 | #' )) 123 | #' ) 124 | #' ) 125 | #' } 126 | #' 127 | #' \dontrun{ 128 | #' # use with react 129 | #' library(htmltools) 130 | #' library(reactR) 131 | #' 132 | #' browsable( 133 | #' tagList( 134 | #' html_dependency_react(), 135 | #' html_dependency_mobx(), 136 | #' div(id="test"), 137 | #' tags$script(HTML(babel_transform( 138 | #' " 139 | #' var obs = mobx.observable({val: null}) 140 | #' var App = mobxReact.observer((props) =>
{props.obs.val}
) 141 | #' 142 | #' ReactDOM.render(, document.querySelector('#test')) 143 | #' 144 | #' setInterval( 145 | #' function() {obs.val++}, 146 | #' 1000 147 | #' ) 148 | #' " 149 | #' ))) 150 | #' ) 151 | #' ) 152 | #' } 153 | 154 | html_dependency_mobx <- function(react = TRUE){ 155 | hd <- htmltools::htmlDependency( 156 | name = "mobx", 157 | version = "4.11.0", 158 | src = system.file("www/mobx",package="reactR"), 159 | script = c("mobx.umd.min.js") 160 | ) 161 | 162 | if(react) { 163 | hd$script <- c(hd$script,"mobx-react-lite.js", "mobx-react.umd.js") 164 | } 165 | 166 | hd 167 | } 168 | -------------------------------------------------------------------------------- /R/meta.R: -------------------------------------------------------------------------------- 1 | #'@keywords internal 2 | react_version <- function(){'18.2.0'} 3 | babel_version <- function(){'6.26.0'} -------------------------------------------------------------------------------- /R/reacttools.R: -------------------------------------------------------------------------------- 1 | # A robust name string is a valid 2 | # - CSS class 3 | # - JavaScript variable name 4 | # - R variable name 5 | robustName <- "^[[:alpha:]_][[:alnum:]_]*$" 6 | 7 | isUpper <- function(s) { 8 | grepl("^[[:upper:]]+$", s) 9 | } 10 | 11 | #' Create a React component 12 | #' 13 | #' @param name Name of the React component, which must start with an upper-case 14 | #' character. 15 | #' @param varArgs Attributes and children of the element to pass along to 16 | #' \code{\link[htmltools]{tag}} as \code{varArgs}. 17 | #' 18 | #' @return An htmltools \code{\link[htmltools]{tag}} object 19 | #' @export 20 | #' 21 | #' @examples 22 | #' component("ParentComponent", 23 | #' list( 24 | #' x = 1, 25 | #' y = 2, 26 | #' component("ChildComponent"), 27 | #' component("OtherChildComponent") 28 | #' ) 29 | #' ) 30 | component <- function(name, varArgs = list()) { 31 | if (length(name) == 0 || !isUpper(substring(name, 1, 1))) { 32 | stop("Component name must be specified and start with an upper case character") 33 | } 34 | component <- htmltools::tag(name, varArgs) 35 | structure(component, class = c("reactR_component", oldClass(component), "list")) 36 | } 37 | 38 | #' React component builder. 39 | #' 40 | #' \code{React} is a syntactically-convenient way to create instances of React 41 | #' components that can be sent to the browser for display. It is a list for 42 | #' which \link[=InternalMethods]{extract methods} are defined, allowing 43 | #' object creation syntax like \code{React$MyComponent(x = 1)} where 44 | #' \code{MyComponent} is a React component you have exposed to Shiny in 45 | #' JavaScript. 46 | #' 47 | #' Internally, the \code{\link{component}} function is used to create the 48 | #' component instance. 49 | #' 50 | #' @examples 51 | #' # Create an instance of ParentComponent with two children, 52 | #' # ChildComponent and OtherChildComponent. 53 | #' React$ParentComponent( 54 | #' x = 1, 55 | #' y = 2, 56 | #' React$ChildComponent(), 57 | #' React$OtherChildComponent() 58 | #' ) 59 | #' @export 60 | React <- structure( 61 | list(), 62 | class = "react_component_builder" 63 | ) 64 | 65 | #' @export 66 | `$.react_component_builder` <- function(x, name) { 67 | function(...) { 68 | component(name, list(...)) 69 | } 70 | } 71 | 72 | #' @export 73 | `[[.react_component_builder` <- `$.react_component_builder` 74 | 75 | #' @export 76 | `$<-.react_component_builder` <- function(x, name, value) { 77 | stop("Assigning to a component constructor is not allowed") 78 | } 79 | 80 | #' @export 81 | `[[<-.react_component_builder` <- `$<-.react_component_builder` 82 | 83 | #' Prepare data that represents a single-element character vector, a React 84 | #' component, or an htmltools tag for sending to the client. 85 | #' 86 | #' Tag lists as returned by \code{htmltools tagList} are not currently 87 | #' supported. 88 | #' 89 | #' @param tag character vector or React component or 90 | #' \code{\link[htmltools]{tag}} 91 | #' 92 | #' @return A reactR markup object suitable for being passed to 93 | #' \code{\link[htmlwidgets]{createWidget}} as widget instance data. 94 | #' @export 95 | reactMarkup <- function(tag) { 96 | stopifnot(inherits(tag, "shiny.tag") 97 | || (is.character(tag) && length(tag) == 1)) 98 | list(tag = tag, class = "reactR_markup") 99 | } 100 | 101 | #' Create a React-based input 102 | #' 103 | #' @param inputId The \code{input} slot that will be used to access the value. 104 | #' @param class Space-delimited list of CSS class names that should identify 105 | #' this input type in the browser. 106 | #' @param dependencies HTML dependencies to include in addition to those 107 | #' supporting React. Must contain at least one dependency, that of the input's 108 | #' implementation. 109 | #' @param default Initial value. 110 | #' @param configuration Static configuration data. 111 | #' @param container Function to generate an HTML element to contain the input. 112 | #' 113 | #' @return Shiny input suitable for inclusion in a UI. 114 | #' @export 115 | #' 116 | #' @examples 117 | #' myInput <- function(inputId, default = "") { 118 | #' # The value of createReactShinyInput should be returned from input constructor functions. 119 | #' createReactShinyInput( 120 | #' inputId, 121 | #' "myinput", 122 | #' # At least one htmlDependency must be provided -- the JavaScript implementation of the input. 123 | #' htmlDependency( 124 | #' name = "my-input", 125 | #' version = "1.0.0", 126 | #' src = "www/mypackage/myinput", 127 | #' package = "mypackage", 128 | #' script = "myinput.js" 129 | #' ), 130 | #' default 131 | #' ) 132 | #' } 133 | createReactShinyInput <- function(inputId, 134 | class, 135 | dependencies, 136 | default = NULL, 137 | configuration = list(), 138 | container = htmltools::tags$div) { 139 | if(length(dependencies) < 1) stop("Must include at least one HTML dependency.") 140 | value <- shiny::restoreInput(id = inputId, default = default) 141 | htmltools::tagList( 142 | html_dependency_corejs(), 143 | html_dependency_react(), 144 | html_dependency_reacttools(), 145 | container(id = inputId, class = class), 146 | htmltools::tags$script(id = sprintf("%s_value", inputId), 147 | type = "application/json", 148 | jsonlite::toJSON(value, auto_unbox = TRUE, null = "null", force = TRUE)), 149 | htmltools::tags$script(id = sprintf("%s_configuration", inputId), 150 | type = "application/json", 151 | jsonlite::toJSON(configuration, auto_unbox = TRUE, null = "null", force = TRUE)), 152 | dependencies 153 | ) 154 | } 155 | -------------------------------------------------------------------------------- /R/scaffold_input.R: -------------------------------------------------------------------------------- 1 | #' Create implementation scaffolding for a React.js-based Shiny input. 2 | #' 3 | #' Add the minimal code required to implement a React.js-based Shiny input to an 4 | #' R package. 5 | #' 6 | #' @param name Name of input 7 | #' @param npmPkgs Optional \href{https://www.npmjs.com/}{NPM} packages upon which 8 | #' this input is based which will be used to populate \code{package.json}. 9 | #' Should be a named list of names to 10 | #' \href{https://docs.npmjs.com/files/package.json/}{versions}. 11 | #' @param edit Automatically open the input's source files after creating the 12 | #' scaffolding. 13 | #' 14 | #' @note This function must be executed from the root directory of the package 15 | #' you wish to add the input to. 16 | #' 17 | #' @export 18 | scaffoldReactShinyInput <- function(name, npmPkgs = NULL, edit = interactive()) { 19 | assertNameValid(name) 20 | package <- getPackage() 21 | 22 | file <- renderFile( 23 | sprintf("R/%s.R", name), 24 | "templates/input_r.txt", 25 | "boilerplate for input constructor", 26 | list( 27 | name = name, 28 | capName = capitalize(name), 29 | package = package 30 | ) 31 | ) 32 | if (edit) fileEdit(file) 33 | 34 | renderFile( 35 | 'package.json', 36 | 'templates/package.json.txt', 37 | 'project metadata', 38 | list(npmPkgs = toDepJSON(npmPkgs)) 39 | ) 40 | 41 | renderFile( 42 | 'webpack.config.js', 43 | 'templates/webpack.config.js.txt', 44 | 'webpack configuration', 45 | list( 46 | name = name, 47 | outputPath = sprintf("inst/www/%s/%s", package, name) 48 | ) 49 | ) 50 | 51 | renderFile( 52 | sprintf('srcjs/%s.jsx', name), 53 | 'templates/input_js.txt', 54 | 'JavaScript implementation', 55 | list( 56 | name = name, 57 | package = package 58 | ) 59 | ) 60 | 61 | renderFile( 62 | 'app.R', 63 | 'templates/input_app.R.txt', 64 | 'example app', 65 | list( 66 | name = name, 67 | package = package 68 | ) 69 | ) 70 | 71 | usethis::use_build_ignore(c("node_modules", "srcjs", "app.R", "package.json", "webpack.config.js", "yarn.lock")) 72 | usethis::use_git_ignore(c("node_modules")) 73 | lapply(c("htmltools", "shiny", "reactR"), usethis::use_package) 74 | 75 | message("To install dependencies from npm run: yarn install") 76 | message("To build JavaScript run: yarn run webpack --mode=development") 77 | } 78 | 79 | -------------------------------------------------------------------------------- /R/scaffold_utils.R: -------------------------------------------------------------------------------- 1 | slurp <- function(file) { 2 | paste(readLines( 3 | system.file(file, package = 'reactR') 4 | ), collapse = "\n") 5 | } 6 | 7 | # invoke file.edit in a way that will bind to the RStudio editor 8 | # when running inside RStudio 9 | fileEdit <- function(file) { 10 | fileEditFunc <- eval(parse(text = "file.edit"), envir = globalenv()) 11 | fileEditFunc(file) 12 | } 13 | 14 | # Perform a series of pattern replacements on str. 15 | # Example: renderTemplate("foo ${x} bar ${y} baz ${x}", list(x = 1, y = 2)) 16 | # Produces: "foo 1 bar 2 baz 1" 17 | renderTemplate <- function(str, substitutions) { 18 | Reduce(function(str, name) { 19 | gsub(paste0("\\$\\{", name, "\\}"), substitutions[[name]], str) 20 | }, names(substitutions), str) 21 | } 22 | 23 | capitalize <- function(s) { 24 | gsub("^(.)", perl = TRUE, replacement = '\\U\\1', s) 25 | } 26 | 27 | toDepJSON <- function(npmPkgs) { 28 | if (is.null(npmPkgs)) { 29 | "" 30 | } else if (!length(names(npmPkgs))) { 31 | stop("Must specify npm package names in the names attributes of npmPkgs") 32 | } else { 33 | paste0(sprintf('"%s": "%s"', names(npmPkgs), npmPkgs), collapse = ",\n") 34 | } 35 | } 36 | 37 | # Wraps renderTemplate for convenient use from scaffold functions. 38 | renderFile <- function(outputFile, templateFile, description = '', substitutions = list()) { 39 | if (!file.exists(outputFile)) { 40 | dir.create(dirname(outputFile), recursive = TRUE, showWarnings = FALSE) 41 | cat(renderTemplate(slurp(templateFile), substitutions), file = outputFile) 42 | message("Created ", description, " ", outputFile) 43 | } else { 44 | message(outputFile, " already exists") 45 | } 46 | outputFile 47 | } 48 | 49 | getPackage <- function() { 50 | if (!file.exists('DESCRIPTION')) { 51 | stop("The current directory doesn't contain a package. You're either in the wrong directory, or need to create a package to house your widget.", call. = FALSE) 52 | } 53 | read.dcf('DESCRIPTION')[[1,"Package"]] 54 | } 55 | 56 | # Constraining names prevents the user from encountering obscure CSS problems 57 | # and JavaScript errors after scaffolding. 58 | assertNameValid <- function(name) { 59 | if (!grepl(robustName, name)) { 60 | msg <- sprintf("Name '%s' is invalid, names must begin with an alphabetic character and must contain only alphabetic and numeric characters", name) 61 | stop(msg, call. = FALSE) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /R/scaffold_widget.R: -------------------------------------------------------------------------------- 1 | #' Create implementation scaffolding for a React.js-based HTML widget 2 | #' 3 | #' Add the minimal code required to implement a React.js-based HTML widget to an 4 | #' R package. 5 | #' 6 | #' @param name Name of widget 7 | #' @param npmPkgs Optional \href{https://www.npmjs.com/}{NPM} packages upon which 8 | #' this widget is based which will be used to populate \code{package.json}. 9 | #' Should be a named list of names to 10 | #' \href{https://docs.npmjs.com/files/package.json/}{versions}. 11 | #' @param edit Automatically open the widget's JavaScript source file after 12 | #' creating the scaffolding. 13 | #' 14 | #' @note This function must be executed from the root directory of the package 15 | #' you wish to add the widget to. 16 | #' 17 | #' @export 18 | scaffoldReactWidget <- function(name, npmPkgs = NULL, edit = interactive()){ 19 | assertNameValid(name) 20 | package <- getPackage() 21 | 22 | addWidgetConstructor(name, package, edit) 23 | addWidgetYAML(name, edit) 24 | addPackageJSON(toDepJSON(npmPkgs)) 25 | addWebpackConfig(name) 26 | addWidgetJS(name, edit) 27 | addExampleApp(name) 28 | 29 | usethis::use_build_ignore(c("node_modules", "srcjs", "app.R", "package.json", "webpack.config.js", "yarn.lock")) 30 | usethis::use_git_ignore(c("node_modules")) 31 | lapply(c("htmltools", "htmlwidgets", "reactR"), usethis::use_package) 32 | 33 | message("To install dependencies from npm run: yarn install") 34 | message("To build JavaScript run: yarn run webpack --mode=development") 35 | } 36 | 37 | addWidgetConstructor <- function(name, package, edit){ 38 | file <- renderFile( 39 | sprintf("R/%s.R", name), 40 | "templates/widget_r.txt", 41 | "boilerplate for widget constructor", 42 | list( 43 | name = name, 44 | package = package, 45 | capName = capitalize(name) 46 | ) 47 | ) 48 | if (edit) fileEdit(file) 49 | } 50 | 51 | addWidgetYAML <- function(name, edit){ 52 | file <- renderFile( 53 | sprintf('inst/htmlwidgets/%s.yaml', name), 54 | "templates/widget_yaml.txt", 55 | "boilerplate for widget dependencies" 56 | ) 57 | if (edit) fileEdit(file) 58 | } 59 | 60 | addPackageJSON <- function(npmPkgs) { 61 | renderFile( 62 | 'package.json', 63 | 'templates/package.json.txt', 64 | 'project metadata', 65 | list(npmPkgs = npmPkgs) 66 | ) 67 | } 68 | 69 | addWebpackConfig <- function(name) { 70 | renderFile( 71 | 'webpack.config.js', 72 | 'templates/webpack.config.js.txt', 73 | 'webpack configuration', 74 | list( 75 | name = name, 76 | outputPath = 'inst/htmlwidgets' 77 | ) 78 | ) 79 | } 80 | 81 | addWidgetJS <- function(name, edit){ 82 | file <- renderFile( 83 | sprintf('srcjs/%s.jsx', name), 84 | 'templates/widget_js.txt', 85 | 'boilerplate for widget JavaScript bindings', 86 | list(name = name) 87 | ) 88 | if (edit) fileEdit(file) 89 | } 90 | 91 | addExampleApp <- function(name) { 92 | renderFile( 93 | 'app.R', 94 | 'templates/widget_app.R.txt', 95 | 'example app', 96 | list( 97 | name = name, 98 | capName = capitalize(name) 99 | ) 100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | # reactR reactR logo 6 | 7 | 8 | 9 | ```{r setup, include = FALSE} 10 | knitr::opts_chunk$set( 11 | collapse = TRUE, 12 | comment = "#>", 13 | fig.path = "man/figures/README-", 14 | out.width = "100%" 15 | ) 16 | ``` 17 | 18 | [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/reactR)](https://cran.r-project.org/package=reactR) 19 | [![R-CMD-check](https://github.com/react-R/reactR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/react-R/reactR/actions/workflows/R-CMD-check.yaml) 20 | 21 | `reactR` provides a set of convenience functions for using [`React`](https://reactjs.org/) in `R` with `htmlwidget` constructor templates and local JavaScript dependencies. The `React` ecosystem is rich with components that can enhance `R` web and Shiny apps. `scaffoldReactWidget()` helps build `htmlwidgets` to integrate these `React` components as `R` `htmlwidgets`. `scaffoldReactShinyInput()` does the same for `Shiny` inputs. The local dependency functions are modeled after the `html_dependency_*` functions from RStudio's [`rmarkdown`](https://github.com/rstudio/rmarkdown) package. 22 | 23 | ## Installation 24 | 25 | You can install reactR from CRAN with `install.packages("reactR")`. For the development version, please use `devtools` as shown below. 26 | 27 | ```R 28 | # install.packages("devtools") 29 | devtools::install_github("react-R/reactR") 30 | ``` 31 | 32 | ## Creating htmlwidgets with React Components 33 | 34 | To wrap a `React` component as an `htmlwidget`, please see the tutorial [htmlwidgets with reactR](https://react-r.github.io/reactR/articles/intro_htmlwidgets.html). Also, there are a variety of examples in the [react-R Github organization](https://github.com/react-R). 35 | 36 | 37 | [`reactable`](https://github.com/glin/reactable) is a very well-built `htmlwidget` leveraging this functionality. 38 | 39 | ## Shiny Outputs and Inputs 40 | 41 | `htmlwidgets` built with `reactR` work well in Shiny as outputs. In version `0.4.0` Alan Dipert has added the ability to easily create React-based official `Shiny` inputs with helpers and scaffolds. Please see the [tutorial](https://react-r.github.io/reactR/articles/intro_inputs.html) for more details. 42 | 43 | ## Examples 44 | 45 | Below are examples of using `reactR` directly. 46 | 47 | ```R 48 | library(reactR) 49 | library(htmltools) 50 | 51 | browsable(tagList( 52 | tags$div(id = "app"), 53 | tags$script( 54 | " 55 | ReactDOM.render( 56 | React.createElement( 57 | 'h1', 58 | null, 59 | 'Powered by React' 60 | ), 61 | document.getElementById('app') 62 | ) 63 | " 64 | ), 65 | #add core-js first to work in RStudio Viewer 66 | html_dependency_corejs(), 67 | html_dependency_react() 68 | )) 69 | ``` 70 | 71 | `reactR` uses the `V8` package if available to transform `JSX` and `ES2015` code with `babel`. 72 | 73 | ```R 74 | library(reactR) 75 | library(htmltools) 76 | 77 | browsable( 78 | tagList( 79 | tags$div(id = "app"), 80 | tags$script( 81 | babel_transform('ReactDOM.render(

Powered By React/JSX

,document.getElementById("app"))') 82 | ), 83 | # add core-js shim first for React in older versions of RStudio Viewer 84 | #html_dependency_corejs(), 85 | html_dependency_react() 86 | ) 87 | ) 88 | ``` 89 | 90 | ## Contributing and Code of Conduct 91 | 92 | We welcome contributors and would love your participation. Please note that this project is released with a [Contributor Code of Conduct](https://github.com/react-R/reactR/blob/master/CONDUCT.md). By participating in this project you agree to abide by the terms. 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # reactR reactR logo 3 | 4 | 5 | 6 | [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/reactR)](https://cran.r-project.org/package=reactR) 7 | [![R-CMD-check](https://github.com/react-R/reactR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/react-R/reactR/actions/workflows/R-CMD-check.yaml) 8 | 9 | `reactR` provides a set of convenience functions for using 10 | [`React`](https://reactjs.org/) in `R` with `htmlwidget` constructor 11 | templates and local JavaScript dependencies. The `React` ecosystem is 12 | rich with components that can enhance `R` web and Shiny apps. 13 | `scaffoldReactWidget()` helps build `htmlwidgets` to integrate these 14 | `React` components as `R` `htmlwidgets`. `scaffoldReactShinyInput()` 15 | does the same for `Shiny` inputs. The local dependency functions are 16 | modeled after the `html_dependency_*` functions from RStudio’s 17 | [`rmarkdown`](https://github.com/rstudio/rmarkdown) package. 18 | 19 | ## Installation 20 | 21 | You can install reactR from CRAN with `install.packages("reactR")`. For 22 | the development version, please use `devtools` as shown below. 23 | 24 | ``` r 25 | # install.packages("devtools") 26 | devtools::install_github("react-R/reactR") 27 | ``` 28 | 29 | ## Creating htmlwidgets with React Components 30 | 31 | To wrap a `React` component as an `htmlwidget`, please see the tutorial 32 | [htmlwidgets with 33 | reactR](https://react-r.github.io/reactR/articles/intro_htmlwidgets.html). 34 | Also, there are a variety of examples in the [react-R Github 35 | organization](https://github.com/react-R). 36 | 37 | [`reactable`](https://github.com/glin/reactable) is a very well-built 38 | `htmlwidget` leveraging this functionality. 39 | 40 | ## Shiny Outputs and Inputs 41 | 42 | `htmlwidgets` built with `reactR` work well in Shiny as outputs. In 43 | version `0.4.0` Alan Dipert has added the ability to easily create 44 | React-based official `Shiny` inputs with helpers and scaffolds. Please 45 | see the 46 | [tutorial](https://react-r.github.io/reactR/articles/intro_inputs.html) 47 | for more details. 48 | 49 | ## Examples 50 | 51 | Below are examples of using `reactR` directly. 52 | 53 | ``` r 54 | library(reactR) 55 | library(htmltools) 56 | 57 | browsable(tagList( 58 | tags$div(id = "app"), 59 | tags$script( 60 | " 61 | ReactDOM.render( 62 | React.createElement( 63 | 'h1', 64 | null, 65 | 'Powered by React' 66 | ), 67 | document.getElementById('app') 68 | ) 69 | " 70 | ), 71 | #add core-js first to work in RStudio Viewer 72 | html_dependency_corejs(), 73 | html_dependency_react() 74 | )) 75 | ``` 76 | 77 | `reactR` uses the `V8` package if available to transform `JSX` and 78 | `ES2015` code with `babel`. 79 | 80 | ``` r 81 | library(reactR) 82 | library(htmltools) 83 | 84 | browsable( 85 | tagList( 86 | tags$div(id = "app"), 87 | tags$script( 88 | babel_transform('ReactDOM.render(

Powered By React/JSX

,document.getElementById("app"))') 89 | ), 90 | # add core-js shim first for React in older versions of RStudio Viewer 91 | #html_dependency_corejs(), 92 | html_dependency_react() 93 | ) 94 | ) 95 | ``` 96 | 97 | ## Contributing and Code of Conduct 98 | 99 | We welcome contributors and would love your participation. Please note 100 | that this project is released with a [Contributor Code of 101 | Conduct](https://github.com/react-R/reactR/blob/master/CONDUCT.md). By 102 | participating in this project you agree to abide by the terms. 103 | -------------------------------------------------------------------------------- /assets/logos/reactR-logo-inkscape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 31 | 36 | 41 | 42 | 51 | 56 | 61 | 62 | 73 | 74 | 96 | 98 | 99 | 101 | image/svg+xml 102 | 104 | 105 | 106 | 107 | 108 | 113 | 116 | 120 | 125 | 126 | 130 | 135 | 139 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /assets/logos/reactR-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/assets/logos/reactR-logo.png -------------------------------------------------------------------------------- /assets/logos/reactR-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 25 | 30 | 35 | 36 | 45 | 50 | 55 | 56 | 66 | 67 | 69 | 70 | 72 | image/svg+xml 73 | 75 | 76 | 77 | 78 | 79 | 82 | 85 | 89 | 93 | 94 | 98 | 102 | 106 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /buildupdate/getreact.R: -------------------------------------------------------------------------------- 1 | # use the very nice rgithub 2 | # devtools::install_github("cscheid/rgithub") 3 | 4 | get_react_latest <- function(){ 5 | gsub( 6 | x=github::get.latest.release("facebook", "react")$content$tag_name, 7 | pattern="v", 8 | replacement="" 9 | ) 10 | } 11 | 12 | get_babel_latest <- function(){ 13 | gsub( 14 | x=github::get.latest.release("babel", "babel-standalone")$content$tag_name, 15 | pattern="release-", 16 | replacement="" 17 | ) 18 | } 19 | 20 | # get newest react 21 | download.file( 22 | url=sprintf( 23 | "https://unpkg.com/react@%s/umd/react.production.min.js", 24 | get_react_latest() 25 | ), 26 | destfile="./inst/www/react/react.min.js" 27 | ) 28 | 29 | # get newest react dom 30 | download.file( 31 | url=sprintf( 32 | "https://unpkg.com/react-dom@%s/umd/react-dom.production.min.js", 33 | get_react_latest() 34 | ), 35 | destfile="./inst/www/react/react-dom.min.js" 36 | ) 37 | 38 | # get newest babel 39 | download.file( 40 | url=sprintf( 41 | "https://unpkg.com/babel-standalone@%s/babel.min.js", 42 | get_babel_latest() 43 | ), 44 | destfile="./inst/www/babel/babel.min.js" 45 | ) 46 | 47 | # write function with newest version 48 | # for use when creating dependencies 49 | cat( 50 | sprintf( 51 | "#'@keywords internal\nreact_version <- function(){'%s'}\nbabel_version <- function(){'%s'}", 52 | get_react_latest(), 53 | get_babel_latest() 54 | ), 55 | file = "./R/meta.R" 56 | ) 57 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * local Windows 10 install, R 4.3.1 3 | * rhub check_for_cran 4 | * winbuilder 5 | * github actions check for cran - ubuntu, mac, windows 6 | 7 | ## R CMD check results 8 | 9 | 0 errors | 0 warnings | 0 note 10 | 11 | ## Reverse dependencies 12 | 13 | reactable - consulted with author who has tested and approved the changes 14 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • reactR 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 |
30 |
85 | 86 | 87 | 88 | 89 |
90 |
91 | 94 | 95 | Content not found. Please use links in the navbar. 96 | 97 |
98 | 99 | 103 | 104 |
105 | 106 | 107 | 108 |
112 | 113 |
114 |

115 |

Site built with pkgdown 2.0.7.

116 |
117 | 118 |
119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/CONDUCT.html: -------------------------------------------------------------------------------- 1 | 2 | Contributor Code of Conduct • reactR 6 | 7 | 8 |
9 |
56 | 57 | 58 | 59 |
60 |
61 | 64 | 65 |
66 | 67 |

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

68 |

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

69 |

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

70 |

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

71 |

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

72 |

This Code of Conduct is adapted from the Contributor Covenant (http:contributor-covenant.org), version 1.0.0, available at http://contributor-covenant.org/version/1/0/0/

73 |
74 | 75 |
76 | 77 | 80 | 81 |
82 | 83 | 84 | 85 |
88 | 89 |
90 |

Site built with pkgdown 2.0.7.

91 |
92 | 93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | License • reactR 6 | 7 | 8 |
9 |
56 | 57 | 58 | 59 |
60 |
61 | 64 | 65 |
YEAR: 2018
66 | COPYRIGHT HOLDER: Kent Russell
67 | 
68 | 69 |
70 | 71 | 74 | 75 |
76 | 77 | 78 | 79 |
82 | 83 |
84 |

Site built with pkgdown 2.0.7.

85 |
86 | 87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | Articles • reactR 6 | 7 | 8 |
9 |
56 | 57 | 58 | 59 |
60 |
61 | 64 | 65 | 76 |
77 |
78 | 79 | 80 |
83 | 84 |
85 |

Site built with pkgdown 2.0.7.

86 |
87 | 88 |
89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /docs/articles/input_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/articles/input_app.jpg -------------------------------------------------------------------------------- /docs/articles/input_sketchpicker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/articles/input_sketchpicker.jpg -------------------------------------------------------------------------------- /docs/articles/input_sketchpicker.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/articles/input_sketchpicker.mp4 -------------------------------------------------------------------------------- /docs/articles/intro_htmlwidgets_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/intro_inputs_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-16.12.0/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-16.7.0/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-16.8.1/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-16.8.6/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-17.0.0/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/intro_reactR_files/react-18.2.0/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-present, Facebook, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/articles/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 25 | 30 | 35 | 36 | 45 | 50 | 55 | 56 | 66 | 67 | 69 | 70 | 72 | image/svg+xml 73 | 75 | 76 | 77 | 78 | 79 | 82 | 85 | 89 | 93 | 94 | 98 | 102 | 106 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/articles/widget_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/articles/widget_app.jpg -------------------------------------------------------------------------------- /docs/articles/widget_app_improved.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/articles/widget_app_improved.jpg -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • reactR 6 | 7 | 8 |
9 |
56 | 57 | 58 | 59 |
60 |
61 |
62 | 65 | 66 | 67 |
  • 68 |

    Facebook Inc. Author, copyright holder. 69 |
    React library in lib, https://reactjs.org/; see AUTHORS for full list of contributors

    70 |
  • 71 |
  • 72 |

    Michel Weststrate. Author, copyright holder. 73 |
    mobx library in lib, https://github.com/mobxjs

    74 |
  • 75 |
  • 76 |

    Kent Russell. Author, maintainer. 77 |
    R interface

    78 |
  • 79 |
  • 80 |

    Alan Dipert. Author. 81 |
    R interface

    82 |
  • 83 |
  • 84 |

    Greg Lin. Author. 85 |
    R interface

    86 |
  • 87 |
88 |
89 |
90 |

Citation

91 | Source: DESCRIPTION 92 |
93 |
94 | 95 | 96 |

Inc F, Weststrate M, Russell K, Dipert A, Lin G (2024). 97 | reactR: React Helpers. 98 | R package version 0.6.1, https://github.com/react-R/reactR. 99 |

100 |
@Manual{,
101 |   title = {reactR: React Helpers},
102 |   author = {Facebook Inc and Michel Weststrate and Kent Russell and Alan Dipert and Greg Lin},
103 |   year = {2024},
104 |   note = {R package version 0.6.1},
105 |   url = {https://github.com/react-R/reactR},
106 | }
107 | 108 |
109 | 110 |
111 | 112 | 113 | 114 |
117 | 118 |
119 |

Site built with pkgdown 2.0.7.

120 |
121 | 122 |
123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/favicon-16x16.png -------------------------------------------------------------------------------- /docs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/favicon-32x32.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/favicon.ico -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 25 | 30 | 35 | 36 | 45 | 50 | 55 | 56 | 66 | 67 | 69 | 70 | 72 | image/svg+xml 73 | 75 | 76 | 77 | 78 | 79 | 82 | 85 | 89 | 93 | 94 | 98 | 102 | 106 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.11 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: 5 | intro_htmlwidgets: intro_htmlwidgets.html 6 | intro_inputs: intro_inputs.html 7 | intro_reactR: intro_reactR.html 8 | last_built: 2024-09-14T13:01Z 9 | 10 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/html_dependency_corejs.html: -------------------------------------------------------------------------------- 1 | 2 | Shim Dependency for React in RStudio Viewer — html_dependency_corejs • reactR 6 | 7 | 8 |
    9 |
    56 | 57 | 58 | 59 |
    60 |
    61 | 66 | 67 |
    68 |

    Add this first for 'React' to work in RStudio Viewer.

    69 |
    70 | 71 |
    72 |
    html_dependency_corejs()
    73 |
    74 | 75 |
    76 |

    Value

    77 | 78 | 79 |

    htmlDependency

    80 | 81 | 82 |
    83 | 84 |
    85 | 88 |
    89 | 90 | 91 |
    94 | 95 |
    96 |

    Site built with pkgdown 2.0.7.

    97 |
    98 | 99 |
    100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/reference/html_dependency_reacttools.html: -------------------------------------------------------------------------------- 1 | 2 | Adds window.reactR.exposeComponents and window.reactR.hydrate — html_dependency_reacttools • reactR 6 | 7 | 8 |
    9 |
    56 | 57 | 58 | 59 |
    60 |
    61 | 66 | 67 |
    68 |

    Adds window.reactR.exposeComponents and window.reactR.hydrate

    69 |
    70 | 71 |
    72 |
    html_dependency_reacttools()
    73 |
    74 | 75 |
    76 |

    Value

    77 | 78 | 79 |

    htmlDependency

    80 | 81 | 82 |
    83 | 84 |
    85 | 88 |
    89 | 90 | 91 |
    94 | 95 |
    96 |

    Site built with pkgdown 2.0.7.

    97 |
    98 | 99 |
    100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/reference/reactMarkup.html: -------------------------------------------------------------------------------- 1 | 2 | Prepare data that represents a single-element character vector, a React 3 | component, or an htmltools tag for sending to the client. — reactMarkup • reactR 9 | 10 | 11 |
    12 |
    59 | 60 | 61 | 62 |
    63 |
    64 | 70 | 71 |
    72 |

    Tag lists as returned by htmltools tagList are not currently 73 | supported.

    74 |
    75 | 76 |
    77 |
    reactMarkup(tag)
    78 |
    79 | 80 |
    81 |

    Arguments

    82 |
    tag
    83 |

    character vector or React component or 84 | tag

    85 | 86 |
    87 |
    88 |

    Value

    89 | 90 | 91 |

    A reactR markup object suitable for being passed to

    92 |

    93 |

    createWidget as widget instance data.

    94 |
    95 | 96 |
    97 | 100 |
    101 | 102 | 103 |
    106 | 107 |
    108 |

    Site built with pkgdown 2.0.7.

    109 |
    110 | 111 |
    112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /404.html 5 | 6 | 7 | /articles/index.html 8 | 9 | 10 | /articles/intro_htmlwidgets.html 11 | 12 | 13 | /articles/intro_inputs.html 14 | 15 | 16 | /articles/intro_reactR.html 17 | 18 | 19 | /authors.html 20 | 21 | 22 | /CONDUCT.html 23 | 24 | 25 | /index.html 26 | 27 | 28 | /LICENSE-text.html 29 | 30 | 31 | /news/index.html 32 | 33 | 34 | /reference/babel_transform.html 35 | 36 | 37 | /reference/component.html 38 | 39 | 40 | /reference/createReactShinyInput.html 41 | 42 | 43 | /reference/html_dependency_corejs.html 44 | 45 | 46 | /reference/html_dependency_mobx.html 47 | 48 | 49 | /reference/html_dependency_react.html 50 | 51 | 52 | /reference/html_dependency_reacttools.html 53 | 54 | 55 | /reference/index.html 56 | 57 | 58 | /reference/React.html 59 | 60 | 61 | /reference/reactMarkup.html 62 | 63 | 64 | /reference/scaffoldReactShinyInput.html 65 | 66 | 67 | /reference/scaffoldReactWidget.html 68 | 69 | 70 | -------------------------------------------------------------------------------- /inst/examples/antd.R: -------------------------------------------------------------------------------- 1 | library(htmltools) 2 | library(reactR) 3 | library(pipeR) 4 | 5 | antd <- htmlDependency( 6 | name = "antd", 7 | version = "2.13.10", 8 | src = c(href="https://unpkg.com/antd@2.13.10/dist"), 9 | script = "antd.min.js", 10 | stylesheet = "antd.min.css" 11 | ) 12 | 13 | 14 | ### menu #### 15 | tl <- tagList( 16 | tags$div(id="app",style="width:25%;"), 17 | tags$script(HTML(babel_transform(' 18 | var menu = 19 | 20 | Navigation One 21 | 22 | 23 | Navigation Two 24 | 25 | 26 | 27 | ReactDOM.render(menu, document.querySelector("#app")) 28 | '))) 29 | ) 30 | 31 | browsable( 32 | tagList( 33 | tl, 34 | html_dependency_react(), 35 | antd 36 | ) 37 | ) 38 | 39 | 40 | ### steps #### 41 | steps <- tag( 42 | "antd.Steps", 43 | list( 44 | current=noquote("{1}"), 45 | tag("antd.Steps.Step", list(title="Finished", description="This is a description." )), 46 | tag("antd.Steps.Step", list(title="In Progress",description="This is a description." )), 47 | tag("antd.Steps.Step", list(title="Waiting", description="This is a description." )) 48 | ) 49 | ) 50 | 51 | tagList( 52 | tags$div(id="stepapp"), 53 | steps %>>% 54 | { 55 | sprintf( 56 | " 57 | const steps = %s; 58 | ReactDOM.render(steps, document.querySelector('#stepapp')); 59 | ", 60 | . 61 | 62 | ) 63 | } %>>% 64 | babel_transform() %>>% 65 | HTML %>>% 66 | tags$script() 67 | ) %>>% 68 | attachDependencies( 69 | list( 70 | html_dependency_react(), 71 | antd 72 | ) 73 | ) %>>% 74 | browsable() 75 | 76 | 77 | ### steps with button #### 78 | steps_button <- list( 79 | list( 80 | title= 'Data', 81 | content= 'Raw Data' 82 | ), 83 | list( 84 | title= 'Model', 85 | content= 'Code for Model' 86 | ), 87 | list( 88 | title= 'Plot', 89 | content= 'Beautiful Plot' 90 | ) 91 | ) %>>% jsonlite::toJSON(auto_unbox=TRUE) 92 | 93 | content_data <- tags$pre( 94 | HTML(paste0( 95 | capture.output(str(iris,max.level=1)), 96 | collapse="
    " 97 | )) 98 | ) 99 | 100 | content_model <- tags$pre("lm(Petal.Width~Petal.Length, data=iris)") 101 | 102 | content_plot <- HTML( 103 | svglite::htmlSVG({plot(lm(Petal.Length~Petal.Width,data=iris),which=1)},standalone=FALSE) 104 | ) 105 | 106 | tagList( 107 | tags$div(id="stepapp", style="width:30%;"), 108 | steps_button %>>% 109 | { 110 | sprintf( 111 | ' 112 | const steps = %s; 113 | 114 | steps[0].content = %s; 115 | steps[1].content = %s; 116 | steps[2].content = 117 | 118 | class App extends React.Component { 119 | constructor(props) { 120 | super(props); 121 | this.state = { 122 | current: 0, 123 | }; 124 | } 125 | next() { 126 | const current = this.state.current + 1; 127 | this.setState({ current }); 128 | } 129 | prev() { 130 | const current = this.state.current - 1; 131 | this.setState({ current }); 132 | } 133 | render() { 134 | const { current } = this.state; 135 | return ( 136 |
    137 | 138 | {steps.map(item => )} 139 | 140 |
    141 | {steps[this.state.current].content} 142 |
    143 |
    144 | { 145 | this.state.current < steps.length - 1 146 | && 147 | this.next()}>Next 148 | } 149 | { 150 | this.state.current === steps.length - 1 151 | && 152 | message.success("Processing complete!")}>Done 153 | } 154 | { 155 | this.state.current > 0 156 | && 157 | this.prev()}> 158 | Previous 159 | 160 | } 161 |
    162 |
    163 | ); 164 | } 165 | } 166 | 167 | ReactDOM.render(, document.querySelector("#stepapp")); 168 | ', 169 | ., 170 | content_data, 171 | content_model, 172 | base64enc::dataURI(rsvg::rsvg_png(charToRaw(content_plot)),mime="image/png") 173 | ) 174 | } %>>% 175 | babel_transform() %>>% 176 | HTML %>>% 177 | tags$script() 178 | ) %>>% 179 | attachDependencies( 180 | list( 181 | html_dependency_react(offline=FALSE), 182 | antd 183 | ) 184 | ) %>>% 185 | browsable() 186 | -------------------------------------------------------------------------------- /inst/examples/office-fabric.R: -------------------------------------------------------------------------------- 1 | library(htmltools) 2 | library(reactR) 3 | 4 | fabric <- htmlDependency( 5 | name = "office-fabric-ui-react", 6 | version = "7.121.12", 7 | src = c(href="https://unpkg.com/office-ui-fabric-react@7.121.12/dist/"), 8 | script = "office-ui-fabric-react.min.js", 9 | stylesheet = "css/fabric.min.css" 10 | ) 11 | 12 | browsable( 13 | tagList( 14 | html_dependency_react(), 15 | fabric 16 | ) 17 | ) 18 | 19 | browsable( 20 | tagList( 21 | html_dependency_react(), 22 | fabric, 23 | tags$div(id = "app-button"), 24 | tags$script(HTML(babel_transform( 25 | " 26 | let btn =
    27 | Command button 28 | 32 | Create account 33 | 34 |
    35 | 36 | ReactDOM.render(btn, document.querySelector('#app-button')); 37 | " 38 | ))) 39 | ) 40 | ) 41 | 42 | 43 | browsable( 44 | tagList( 45 | html_dependency_react(), 46 | fabric, 47 | tags$div(id="pivot-example"), 48 | tags$script(HTML(babel_transform( 49 | " 50 | class PivotBasicExample extends React.Component { 51 | render() { 52 | return ( 53 |
    54 | 55 | 56 | Pivot #1 57 | 58 | 59 | Pivot #2 60 | 61 | 62 | Pivot #3 63 | 64 | 65 |
    66 | ); 67 | } 68 | } 69 | ReactDOM.render(, document.querySelector('#pivot-example')); 70 | " 71 | ))) 72 | ) 73 | ) 74 | -------------------------------------------------------------------------------- /inst/templates/input_app.R.txt: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(${package}) 3 | 4 | ui <- fluidPage( 5 | titlePanel("reactR Input Example"), 6 | ${name}Input("textInput"), 7 | textOutput("textOutput") 8 | ) 9 | 10 | server <- function(input, output, session) { 11 | output$textOutput <- renderText({ 12 | sprintf("You entered: %s", input$textInput) 13 | }) 14 | } 15 | 16 | shinyApp(ui, server) 17 | -------------------------------------------------------------------------------- /inst/templates/input_js.txt: -------------------------------------------------------------------------------- 1 | import { reactShinyInput } from 'reactR'; 2 | 3 | const TextInput = ({ configuration, value, setValue }) => { 4 | return setValue(e.target.value)}/>; 5 | }; 6 | 7 | reactShinyInput('.${name}', '${package}.${name}', TextInput); 8 | -------------------------------------------------------------------------------- /inst/templates/input_r.txt: -------------------------------------------------------------------------------- 1 | #' 2 | #' 3 | #' 4 | #' 5 | #' @importFrom reactR createReactShinyInput 6 | #' @importFrom htmltools htmlDependency tags 7 | #' 8 | #' @export 9 | ${name}Input <- function(inputId, default = "") { 10 | reactR::createReactShinyInput( 11 | inputId, 12 | "${name}", 13 | htmltools::htmlDependency( 14 | name = "${name}-input", 15 | version = "1.0.0", 16 | src = "www/${package}/${name}", 17 | package = "${package}", 18 | script = "${name}.js" 19 | ), 20 | default, 21 | list(), 22 | htmltools::tags$span 23 | ) 24 | } 25 | 26 | #' 27 | #' 28 | #' 29 | #' 30 | #' @export 31 | update${capName}Input <- function(session, inputId, value, configuration = NULL) { 32 | message <- list(value = value) 33 | if (!is.null(configuration)) message$configuration <- configuration 34 | session$sendInputMessage(inputId, message); 35 | } 36 | -------------------------------------------------------------------------------- /inst/templates/package.json.txt: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | ${npmPkgs} 5 | }, 6 | "devDependencies": { 7 | "webpack": "^4.27.1", 8 | "webpack-cli": "^3.1.2", 9 | "@babel/core": "^7.2.0", 10 | "babel-loader": "^8.0.4", 11 | "@babel/preset-env": "^7.2.0", 12 | "@babel/preset-react": "^7.0.0", 13 | "css-loader": "^5.0.1", 14 | "style-loader": "^2.0.0" 15 | }, 16 | "scripts": { 17 | "watch": "webpack --watch", 18 | "build": "webpack" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /inst/templates/webpack.config.js.txt: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | entry: path.join(__dirname, 'srcjs', '${name}.jsx'), 5 | output: { 6 | path: path.join(__dirname, '${outputPath}'), 7 | filename: '${name}.js' 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.jsx?$/, 13 | loader: 'babel-loader', 14 | options: { 15 | presets: ['@babel/preset-env', '@babel/preset-react'] 16 | } 17 | }, 18 | // For CSS so that import "path/style.css"; works 19 | { 20 | test: /\.css$/, 21 | use: ['style-loader', 'css-loader'] 22 | } 23 | ] 24 | }, 25 | externals: { 26 | 'react': 'window.React', 27 | 'react-dom': 'window.ReactDOM', 28 | 'reactR': 'window.reactR' 29 | }, 30 | stats: { 31 | colors: true 32 | }, 33 | devtool: 'source-map' 34 | }; 35 | -------------------------------------------------------------------------------- /inst/templates/widget_app.R.txt: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(${name}) 3 | 4 | ui <- fluidPage( 5 | titlePanel("reactR HTMLWidget Example"), 6 | ${name}Output('widgetOutput') 7 | ) 8 | 9 | server <- function(input, output, session) { 10 | output$widgetOutput <- render${capName}( 11 | ${name}("Hello world!") 12 | ) 13 | } 14 | 15 | shinyApp(ui, server) 16 | -------------------------------------------------------------------------------- /inst/templates/widget_js.txt: -------------------------------------------------------------------------------- 1 | import { reactWidget } from 'reactR'; 2 | 3 | reactWidget('${name}', 'output', {}, {}); 4 | -------------------------------------------------------------------------------- /inst/templates/widget_r.txt: -------------------------------------------------------------------------------- 1 | #' 2 | #' 3 | #' 4 | #' 5 | #' @import htmlwidgets 6 | #' 7 | #' @export 8 | ${name} <- function(message, width = NULL, height = NULL, elementId = NULL) { 9 | 10 | # describe a React component to send to the browser for rendering. 11 | component <- reactR::reactMarkup(htmltools::tag("div", list(message))) 12 | 13 | # create widget 14 | htmlwidgets::createWidget( 15 | name = '${name}', 16 | component, 17 | width = width, 18 | height = height, 19 | package = '${package}', 20 | elementId = elementId 21 | ) 22 | } 23 | 24 | #' Called by HTMLWidgets to produce the widget's root element. 25 | #' @noRd 26 | widget_html.${name} <- function(id, style, class, ...) { 27 | htmltools::tagList( 28 | # Necessary for RStudio viewer version < 1.2 29 | reactR::html_dependency_corejs(), 30 | reactR::html_dependency_react(), 31 | reactR::html_dependency_reacttools(), 32 | htmltools::tags$div(id = id, class = class, style = style) 33 | ) 34 | } 35 | 36 | #' Shiny bindings for ${name} 37 | #' 38 | #' Output and render functions for using ${name} within Shiny 39 | #' applications and interactive Rmd documents. 40 | #' 41 | #' @param outputId output variable to read from 42 | #' @param width,height Must be a valid CSS unit (like \code{'100\%'}, 43 | #' \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a 44 | #' string and have \code{'px'} appended. 45 | #' @param expr An expression that generates a ${name} 46 | #' @param env The environment in which to evaluate \code{expr}. 47 | #' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This 48 | #' is useful if you want to save an expression in a variable. 49 | #' 50 | #' @name ${name}-shiny 51 | #' 52 | #' @export 53 | ${name}Output <- function(outputId, width = '100%', height = '400px'){ 54 | htmlwidgets::shinyWidgetOutput(outputId, '${name}', width, height, package = '${package}') 55 | } 56 | 57 | #' @rdname ${name}-shiny 58 | #' @export 59 | render${capName} <- function(expr, env = parent.frame(), quoted = FALSE) { 60 | if (!quoted) { expr <- substitute(expr) } # force quoted 61 | htmlwidgets::shinyRenderWidget(expr, ${name}Output, env, quoted = TRUE) 62 | } 63 | -------------------------------------------------------------------------------- /inst/templates/widget_yaml.txt: -------------------------------------------------------------------------------- 1 | # (uncomment to add a dependency) 2 | # dependencies: 3 | # - name: 4 | # version: 5 | # src: 6 | # script: 7 | # stylesheet: 8 | 9 | -------------------------------------------------------------------------------- /inst/www/core-js/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 Denis Pushkarev 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 | -------------------------------------------------------------------------------- /inst/www/core-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@babel/cli": "^7.7.7", 4 | "@babel/core": "^7.7.7", 5 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4", 6 | "@babel/plugin-proposal-optional-catch-binding": "^7.7.4", 7 | "@babel/plugin-proposal-optional-chaining": "^7.7.5", 8 | "@babel/plugin-transform-arrow-functions": "^7.7.4", 9 | "@babel/plugin-transform-block-scoped-functions": "^7.7.4", 10 | "@babel/plugin-transform-block-scoping": "^7.7.4", 11 | "@babel/plugin-transform-classes": "^7.7.4", 12 | "@babel/plugin-transform-computed-properties": "^7.7.4", 13 | "@babel/plugin-transform-destructuring": "^7.7.4", 14 | "@babel/plugin-transform-exponentiation-operator": "^7.7.4", 15 | "@babel/plugin-transform-literals": "^7.7.4", 16 | "@babel/plugin-transform-member-expression-literals": "^7.7.4", 17 | "@babel/plugin-transform-parameters": "^7.7.7", 18 | "@babel/plugin-transform-property-literals": "^7.7.4", 19 | "@babel/plugin-transform-shorthand-properties": "^7.7.4", 20 | "@babel/plugin-transform-spread": "^7.7.4", 21 | "@babel/plugin-transform-template-literals": "^7.7.4", 22 | "babel-loader": "^8.0.6", 23 | "babel-plugin-transform-es2015-modules-simple-commonjs": "~0.3.0", 24 | "babel-plugin-transform-for-of-as-array": "^1.1.1", 25 | "es-observable": "git+https://github.com/tc39/proposal-observable.git#bf4d87144b6189e793593868e3c022eb51a7d292", 26 | "eslint": "^6.8.0", 27 | "eslint-import-resolver-webpack": "^0.12.0", 28 | "eslint-plugin-import": "^2.19.1", 29 | "eslint-plugin-node": "^10.0.0", 30 | "eslint-plugin-optimize-regex": "^1.1.7", 31 | "eslint-plugin-qunit": "^4.0.0", 32 | "eslint-plugin-sonarjs": "^0.5.0", 33 | "eslint-plugin-unicorn": "^15.0.0", 34 | "grunt": "^1.0.4", 35 | "grunt-cli": "^1.3.2", 36 | "grunt-contrib-clean": "^2.0.0", 37 | "grunt-contrib-copy": "^1.0.0", 38 | "grunt-contrib-uglify": "^4.0.1", 39 | "grunt-karma": "^3.0.2", 40 | "grunt-webpack": "^3.1.3", 41 | "karma": "^4.4.1", 42 | "karma-chrome-launcher": "^3.1.0", 43 | "karma-phantomjs-launcher": "~1.0.4", 44 | "karma-qunit": "^4.0.0", 45 | "lerna": "^3.19.0", 46 | "moon-unit": "^0.2.2", 47 | "phantomjs-prebuilt": "~2.1.16", 48 | "promises-aplus-tests": "^2.1.2", 49 | "puppeteer": "~2.0.0", 50 | "qunit": "~2.9.3", 51 | "webpack": "^4.41.4" 52 | }, 53 | "license": "MIT", 54 | "repository": { 55 | "type": "git", 56 | "url": "https://github.com/zloirock/core-js.git" 57 | }, 58 | "scripts": { 59 | "bootstrap": "lerna bootstrap --no-ci", 60 | "build": "grunt clean copy && npm run bootstrap && npm run build-compat && grunt bundle uglify", 61 | "build-compat": "npm run build-compat-data && npm run build-compat-entries && npm run build-compat-modules-by-versions", 62 | "build-compat-data": "node packages/core-js-compat/src/build-data", 63 | "build-compat-entries": "node packages/core-js-compat/src/build-entries", 64 | "build-compat-modules-by-versions": "node packages/core-js-compat/src/build-modules-by-versions", 65 | "lint": "grunt clean copy && npm run bootstrap && npm run build-compat && eslint ./", 66 | "unit-tests": "grunt clean copy && npm run bootstrap && npm run build-compat && grunt bundle webpack:helpers webpack:tests karma:tests", 67 | "unit-tests-pure": "grunt clean copy && npm run build-compat && grunt webpack:helpers webpack:pure karma:pure", 68 | "bundle-promises-tests": "grunt webpack:promises-aplus-tests", 69 | "promises-tests": "promises-aplus-tests tests/promises-aplus/adapter --timeout 1000", 70 | "observables-tests": "babel node_modules/es-observable/test/ -d tests/bundles/observables-tests/ && node tests/observables/adapter && node tests/observables/adapter-pure", 71 | "commonjs-tests": "node tests/commonjs", 72 | "commonjs-entries-content": "node tests/commonjs-entries-content", 73 | "targets-parser-tests": "node tests/targets-parser", 74 | "test": "grunt clean copy && npm run bootstrap && npm run build-compat && eslint ./ && grunt webpack:helpers webpack:tests bundle uglify karma:tests webpack:helpers webpack:pure karma:pure && npm run promises-tests && npm run observables-tests && npm run commonjs-tests && npm run commonjs-entries-content && npm run targets-parser-tests" 75 | }, 76 | "engines": { 77 | "node": ">=8.9.0" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /inst/www/mobx/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Michel Weststrate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /inst/www/mobx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mobx", 3 | "version": "5.10.1", 4 | "description": "Simple, scalable state management.", 5 | "main": "lib/mobx.js", 6 | "umd:main": "lib/mobx.umd.js", 7 | "module": "lib/mobx.module.js", 8 | "browser": { 9 | "./lib/mobx.js": "./lib/mobx.js", 10 | "./lib/mobx.module.js": "./lib/mobx.module.js" 11 | }, 12 | "unpkg": "lib/mobx.umd.min.js", 13 | "jsnext:main": "lib/mobx.module.js", 14 | "react-native": "lib/mobx.module.js", 15 | "typings": "lib/mobx.d.ts", 16 | "scripts": { 17 | "test": "jest", 18 | "watch": "jest --watch", 19 | "test:mixed-versions": "jest --testRegex mixed-versions", 20 | "test:all": "yarn lint && yarn small-build && yarn jest -i && yarn test:flow && yarn test:mixed-versions", 21 | "test:webpack": "node scripts/webpack-regression-tests.js", 22 | "test:flow": "node_modules/.bin/flow check", 23 | "test:performance": "npm run small-build && PERSIST=true time node --expose-gc test/perf/index.js", 24 | "test:travis": "yarn test:all && yarn test:performance && yarn test -i --coverage && yarn test:webpack && yarn size", 25 | "prettier": "prettier \"**/*.js\" \"**/*.jsx\" \"**/*.tsx\" \"**/*.ts\"", 26 | "_prepublish": "npm run small-build", 27 | "quick-build": "tsc --pretty", 28 | "small-build": "node scripts/build.js", 29 | "lint": "eslint src/**/*.ts", 30 | "size": "size-limit", 31 | "publish-script": "node scripts/publish.js" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/mobxjs/mobx.git" 36 | }, 37 | "author": "Michel Weststrate", 38 | "license": "MIT", 39 | "bugs": { 40 | "url": "https://github.com/mobxjs/mobx/issues" 41 | }, 42 | "files": [ 43 | "lib", 44 | "LICENSE" 45 | ], 46 | "homepage": "https://mobx.js.org/", 47 | "devDependencies": { 48 | "@babel/core": "^7.3.4", 49 | "@babel/plugin-proposal-class-properties": "^7.3.4", 50 | "@babel/plugin-proposal-decorators": "^7.3.0", 51 | "@babel/plugin-transform-runtime": "^7.3.4", 52 | "@babel/preset-env": "^7.3.4", 53 | "@babel/runtime": "^7.3.4", 54 | "@types/jest": "^24.0.11", 55 | "@types/node": "^11.11.3", 56 | "@typescript-eslint/eslint-plugin": "^1.4.2", 57 | "babel-jest": "^24.5.0", 58 | "chalk": "^1.1.3", 59 | "coveralls": "^3.0.3", 60 | "eslint": "^5.15.2", 61 | "flow-bin": "^0.59.0", 62 | "fs-extra": "^7.0.1", 63 | "husky": "^1.3.1", 64 | "iterall": "^1.2.2", 65 | "jest": "^24.5.0", 66 | "lint-staged": "^8.1.5", 67 | "prettier": "^1.16.4", 68 | "rollup": "^1.6.0", 69 | "rollup-plugin-filesize": "^6.0.1", 70 | "rollup-plugin-node-resolve": "^4.0.1", 71 | "rollup-plugin-replace": "^2.1.0", 72 | "rollup-plugin-terser": "^4.0.4", 73 | "serializr": "^1.5.1", 74 | "shelljs": "^0.8.3", 75 | "size-limit": "^1.3.3", 76 | "tape": "^4.10.1", 77 | "ts-jest": "^24.0.0", 78 | "tslib": "^1.9.3", 79 | "typescript": "^3.3.3333" 80 | }, 81 | "dependencies": {}, 82 | "keywords": [ 83 | "mobx", 84 | "mobservable", 85 | "observable", 86 | "react-component", 87 | "react", 88 | "reactjs", 89 | "reactive", 90 | "model", 91 | "frp", 92 | "functional-reactive-programming", 93 | "state management", 94 | "data flow" 95 | ], 96 | "lint-staged": { 97 | "*.{ts,tsx,js,jsx}": [ 98 | "prettier --write", 99 | "git add" 100 | ] 101 | }, 102 | "jest": { 103 | "globals": { 104 | "ts-jest": { 105 | "tsConfig": "tsconfig.test.json" 106 | } 107 | }, 108 | "transform": { 109 | "^.+\\.tsx?$": "ts-jest", 110 | "^.+\\.jsx?$": "babel-jest" 111 | }, 112 | "testRegex": "test/base/.*\\.(t|j)sx?$", 113 | "moduleFileExtensions": [ 114 | "ts", 115 | "tsx", 116 | "js", 117 | "jsx", 118 | "json" 119 | ], 120 | "testPathIgnorePatterns": [ 121 | "/node_modules/", 122 | "/\\./" 123 | ], 124 | "watchPathIgnorePatterns": [ 125 | "/node_modules/" 126 | ] 127 | }, 128 | "husky": { 129 | "hooks": { 130 | "pre-commit": "lint-staged" 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /inst/www/react-tools/react-tools.js: -------------------------------------------------------------------------------- 1 | (function(s,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(s=typeof globalThis<"u"?globalThis:s||self,u(s.reactR={}))})(this,function(s){"use strict";function u(n,t){if(typeof t=="string")return t;if(t.name[0]===t.name[0].toUpperCase()&&!n.hasOwnProperty(t.name))throw new Error("Unknown component: "+t.name);for(let i in t.attribs)g(t.attribs[i])&&(t.attribs[i]=u(n,t.attribs[i]));for(var a=n.hasOwnProperty(t.name)?n[t.name]:t.name,r=[a,t.attribs],e=0;e{this.props.message.toUpperCase()}; 19 | } 20 | } 21 | 22 | const FunctionalShout = ({ message }) => { 23 | return {message.toUpperCase()}; 24 | } 25 | 26 | class TodoList extends React.Component { 27 | render() { 28 | return
      29 | {this.props.children.map((child, i) => { 30 | return
    1. {child}
    2. ; 31 | })} 32 |
    33 | } 34 | } 35 | 36 | // Converts a parse-xml style tree to an htmltools::tag style tree of JSON. 37 | function objectToTag(obj) { 38 | return { 39 | name: obj.name, 40 | attribs: obj.attributes, 41 | children: obj.children.map(child => { 42 | if (child.type === 'text') { 43 | return child.text; 44 | } else { 45 | return objectToTag(child); 46 | } 47 | }) 48 | } 49 | } 50 | 51 | // Converts a string of markup to an htmltools::tag style tree of JSON. 52 | function stringToTag(str) { 53 | return objectToTag(parseXml(str).children[0]); 54 | } 55 | 56 | // Compares two parse-xml style trees for "deep" equality 57 | function xmlEqual(x1, x2) { 58 | if (x1.type === 'text' 59 | && x2.type === 'text' 60 | && x1.text === x2.text) 61 | return true; 62 | return x1.name === x2.name 63 | // Test attributes for equality 64 | && Object.keys(x1).length === Object.keys(x2).length 65 | && Object.keys(x1).every(k => x1[k] === x2[k]) 66 | // Test children for equality 67 | && x1.children.length === x2.children.length 68 | && x1.children.every((child, i) => xmlEqual(child, x2.children[i])) 69 | } 70 | 71 | describe('window.reactR', () => { 72 | describe('#hydrate() with HTML', () => { 73 | it('hydrates an HTML5 component with a text child', () => { 74 | const markup = '

    Hello

    '; 75 | assert.equal( 76 | renderToString(parse(markup)), 77 | renderToString(hydrate({}, stringToTag(markup))) 78 | ) 79 | }) 80 | it('hydrates nested HTML5 components', () => { 81 | const markup = '

    Hello

    Oh, hello.

    ' 82 | assert.equal( 83 | renderToString(parse(markup)), 84 | renderToString(hydrate({}, stringToTag(markup))) 85 | ) 86 | }) 87 | }); 88 | describe('#hydrate() with Components', () => { 89 | it('should throw an exception with an unknown component', () => { 90 | assert.throws(() => { 91 | hydrate({ Shout: Shout }, stringToTag('')) 92 | }, Error, /Unknown component/); 93 | }); 94 | }) 95 | }); 96 | -------------------------------------------------------------------------------- /man/React.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reacttools.R 3 | \docType{data} 4 | \name{React} 5 | \alias{React} 6 | \title{React component builder.} 7 | \format{ 8 | An object of class \code{react_component_builder} of length 0. 9 | } 10 | \usage{ 11 | React 12 | } 13 | \description{ 14 | \code{React} is a syntactically-convenient way to create instances of React 15 | components that can be sent to the browser for display. It is a list for 16 | which \link[=InternalMethods]{extract methods} are defined, allowing 17 | object creation syntax like \code{React$MyComponent(x = 1)} where 18 | \code{MyComponent} is a React component you have exposed to Shiny in 19 | JavaScript. 20 | } 21 | \details{ 22 | Internally, the \code{\link{component}} function is used to create the 23 | component instance. 24 | } 25 | \examples{ 26 | # Create an instance of ParentComponent with two children, 27 | # ChildComponent and OtherChildComponent. 28 | React$ParentComponent( 29 | x = 1, 30 | y = 2, 31 | React$ChildComponent(), 32 | React$OtherChildComponent() 33 | ) 34 | } 35 | \keyword{datasets} 36 | -------------------------------------------------------------------------------- /man/babel_transform.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/babel.R 3 | \name{babel_transform} 4 | \alias{babel_transform} 5 | \title{Transform Code with Babel} 6 | \usage{ 7 | babel_transform(code = "") 8 | } 9 | \arguments{ 10 | \item{code}{\code{character}} 11 | } 12 | \value{ 13 | transformed \code{character} 14 | } 15 | \description{ 16 | Helper function to use \code{V8} with \code{Babel} so we can 17 | avoid a JSX transformer with using \code{reactR}. 18 | } 19 | \examples{ 20 | \dontrun{ 21 | library(reactR) 22 | babel_transform('
    react div
    ') 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /man/component.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reacttools.R 3 | \name{component} 4 | \alias{component} 5 | \title{Create a React component} 6 | \usage{ 7 | component(name, varArgs = list()) 8 | } 9 | \arguments{ 10 | \item{name}{Name of the React component, which must start with an upper-case 11 | character.} 12 | 13 | \item{varArgs}{Attributes and children of the element to pass along to 14 | \code{\link[htmltools]{tag}} as \code{varArgs}.} 15 | } 16 | \value{ 17 | An htmltools \code{\link[htmltools]{tag}} object 18 | } 19 | \description{ 20 | Create a React component 21 | } 22 | \examples{ 23 | component("ParentComponent", 24 | list( 25 | x = 1, 26 | y = 2, 27 | component("ChildComponent"), 28 | component("OtherChildComponent") 29 | ) 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /man/createReactShinyInput.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reacttools.R 3 | \name{createReactShinyInput} 4 | \alias{createReactShinyInput} 5 | \title{Create a React-based input} 6 | \usage{ 7 | createReactShinyInput( 8 | inputId, 9 | class, 10 | dependencies, 11 | default = NULL, 12 | configuration = list(), 13 | container = htmltools::tags$div 14 | ) 15 | } 16 | \arguments{ 17 | \item{inputId}{The \code{input} slot that will be used to access the value.} 18 | 19 | \item{class}{Space-delimited list of CSS class names that should identify 20 | this input type in the browser.} 21 | 22 | \item{dependencies}{HTML dependencies to include in addition to those 23 | supporting React. Must contain at least one dependency, that of the input's 24 | implementation.} 25 | 26 | \item{default}{Initial value.} 27 | 28 | \item{configuration}{Static configuration data.} 29 | 30 | \item{container}{Function to generate an HTML element to contain the input.} 31 | } 32 | \value{ 33 | Shiny input suitable for inclusion in a UI. 34 | } 35 | \description{ 36 | Create a React-based input 37 | } 38 | \examples{ 39 | myInput <- function(inputId, default = "") { 40 | # The value of createReactShinyInput should be returned from input constructor functions. 41 | createReactShinyInput( 42 | inputId, 43 | "myinput", 44 | # At least one htmlDependency must be provided -- the JavaScript implementation of the input. 45 | htmlDependency( 46 | name = "my-input", 47 | version = "1.0.0", 48 | src = "www/mypackage/myinput", 49 | package = "mypackage", 50 | script = "myinput.js" 51 | ), 52 | default 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /man/html_dependency_corejs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dependencies.R 3 | \name{html_dependency_corejs} 4 | \alias{html_dependency_corejs} 5 | \title{Shim Dependency for React in RStudio Viewer} 6 | \usage{ 7 | html_dependency_corejs() 8 | } 9 | \value{ 10 | \code{\link[htmltools]{htmlDependency}} 11 | } 12 | \description{ 13 | Add this first for 'React' to work in RStudio Viewer. 14 | } 15 | -------------------------------------------------------------------------------- /man/html_dependency_mobx.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dependencies.R 3 | \name{html_dependency_mobx} 4 | \alias{html_dependency_mobx} 5 | \title{Dependencies for 'mobx'} 6 | \usage{ 7 | html_dependency_mobx(react = TRUE) 8 | } 9 | \arguments{ 10 | \item{react}{\code{logical} to add react 'mobx' dependencies.} 11 | } 12 | \value{ 13 | \code{\link[htmltools]{htmlDependency}} 14 | } 15 | \description{ 16 | Add JavaScript 'mobx' and 'mobx-react' dependency. When using with 'react', the order 17 | of the dependencies is important, so please add \code{html_dependency_react()} before 18 | \code{html_dependency_mobx()}. 19 | } 20 | \examples{ 21 | if(interactive()) { 22 | 23 | library(htmltools) 24 | library(reactR) 25 | 26 | browsable( 27 | tagList( 28 | html_dependency_mobx(react = FALSE), 29 | div(id="test"), 30 | tags$script(HTML( 31 | " 32 | var obs = mobx.observable({val: null}) 33 | mobx.autorun(function() { 34 | document.querySelector('#test').innerText = obs.val 35 | }) 36 | setInterval( 37 | function() {obs.val++}, 38 | 1000 39 | ) 40 | " 41 | )) 42 | ) 43 | ) 44 | } 45 | 46 | \dontrun{ 47 | # use with react 48 | library(htmltools) 49 | library(reactR) 50 | 51 | browsable( 52 | tagList( 53 | html_dependency_react(), 54 | html_dependency_mobx(), 55 | div(id="test"), 56 | tags$script(HTML(babel_transform( 57 | " 58 | var obs = mobx.observable({val: null}) 59 | var App = mobxReact.observer((props) =>
    {props.obs.val}
    ) 60 | 61 | ReactDOM.render(, document.querySelector('#test')) 62 | 63 | setInterval( 64 | function() {obs.val++}, 65 | 1000 66 | ) 67 | " 68 | ))) 69 | ) 70 | ) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /man/html_dependency_react.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dependencies.R 3 | \name{html_dependency_react} 4 | \alias{html_dependency_react} 5 | \title{Dependencies for React} 6 | \usage{ 7 | html_dependency_react(offline = TRUE) 8 | } 9 | \arguments{ 10 | \item{offline}{\code{logical} to use local file dependencies. If \code{FALSE}, 11 | then the dependencies use the Facebook cdn as its \code{src}. 12 | To use with \code{JSX} see \code{\link{babel_transform}}.} 13 | } 14 | \value{ 15 | \code{\link[htmltools]{htmlDependency}} 16 | } 17 | \description{ 18 | Add JavaScript 'React' dependency. For this to work in RStudio Viewer, also include 19 | \code{\link{html_dependency_corejs}}. 20 | } 21 | \examples{ 22 | library(reactR) 23 | library(htmltools) 24 | 25 | tagList( 26 | tags$script( 27 | " 28 | ReactDOM.render( 29 | React.createElement( 30 | 'h1', 31 | null, 32 | 'Powered by React' 33 | ), 34 | document.body 35 | ) 36 | " 37 | ), 38 | #add core-js first to work in RStudio Viewer 39 | html_dependency_corejs(), 40 | html_dependency_react() #offline=FALSE for CDN 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /man/html_dependency_reacttools.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dependencies.R 3 | \name{html_dependency_reacttools} 4 | \alias{html_dependency_reacttools} 5 | \title{Adds window.reactR.exposeComponents and window.reactR.hydrate} 6 | \usage{ 7 | html_dependency_reacttools() 8 | } 9 | \value{ 10 | \code{\link[htmltools]{htmlDependency}} 11 | } 12 | \description{ 13 | Adds window.reactR.exposeComponents and window.reactR.hydrate 14 | } 15 | -------------------------------------------------------------------------------- /man/reactMarkup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reacttools.R 3 | \name{reactMarkup} 4 | \alias{reactMarkup} 5 | \title{Prepare data that represents a single-element character vector, a React 6 | component, or an htmltools tag for sending to the client.} 7 | \usage{ 8 | reactMarkup(tag) 9 | } 10 | \arguments{ 11 | \item{tag}{character vector or React component or 12 | \code{\link[htmltools]{tag}}} 13 | } 14 | \value{ 15 | A reactR markup object suitable for being passed to 16 | \code{\link[htmlwidgets]{createWidget}} as widget instance data. 17 | } 18 | \description{ 19 | Tag lists as returned by \code{htmltools tagList} are not currently 20 | supported. 21 | } 22 | -------------------------------------------------------------------------------- /man/scaffoldReactShinyInput.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scaffold_input.R 3 | \name{scaffoldReactShinyInput} 4 | \alias{scaffoldReactShinyInput} 5 | \title{Create implementation scaffolding for a React.js-based Shiny input.} 6 | \usage{ 7 | scaffoldReactShinyInput(name, npmPkgs = NULL, edit = interactive()) 8 | } 9 | \arguments{ 10 | \item{name}{Name of input} 11 | 12 | \item{npmPkgs}{Optional \href{https://www.npmjs.com/}{NPM} packages upon which 13 | this input is based which will be used to populate \code{package.json}. 14 | Should be a named list of names to 15 | \href{https://docs.npmjs.com/files/package.json/}{versions}.} 16 | 17 | \item{edit}{Automatically open the input's source files after creating the 18 | scaffolding.} 19 | } 20 | \description{ 21 | Add the minimal code required to implement a React.js-based Shiny input to an 22 | R package. 23 | } 24 | \note{ 25 | This function must be executed from the root directory of the package 26 | you wish to add the input to. 27 | } 28 | -------------------------------------------------------------------------------- /man/scaffoldReactWidget.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scaffold_widget.R 3 | \name{scaffoldReactWidget} 4 | \alias{scaffoldReactWidget} 5 | \title{Create implementation scaffolding for a React.js-based HTML widget} 6 | \usage{ 7 | scaffoldReactWidget(name, npmPkgs = NULL, edit = interactive()) 8 | } 9 | \arguments{ 10 | \item{name}{Name of widget} 11 | 12 | \item{npmPkgs}{Optional \href{https://www.npmjs.com/}{NPM} packages upon which 13 | this widget is based which will be used to populate \code{package.json}. 14 | Should be a named list of names to 15 | \href{https://docs.npmjs.com/files/package.json/}{versions}.} 16 | 17 | \item{edit}{Automatically open the widget's JavaScript source file after 18 | creating the scaffolding.} 19 | } 20 | \description{ 21 | Add the minimal code required to implement a React.js-based HTML widget to an 22 | R package. 23 | } 24 | \note{ 25 | This function must be executed from the root directory of the package 26 | you wish to add the widget to. 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tools", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "vite build", 7 | "test": "vitest run" 8 | }, 9 | "devDependencies": { 10 | "@rgrove/parse-xml": "^4.1.0", 11 | "html-react-parser": "^5.1.1", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "vite": "^5.0.11", 15 | "vitest": "^1.2.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /reactR.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: XeLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /srcjs/input.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This default receiveMessage implementation expects data to contain whole 3 | * configuration and value properties. If either is present, it will be set and 4 | * the component will be re-rendered. Because receiveMessage is typically used 5 | * by input authors to perform incremental updates, this default implementation 6 | * can be overriden by the user with the receiveMessage arguments to 7 | * reactShinyInput. 8 | */ 9 | function defaultReceiveMessage(el, { configuration, value }) { 10 | let dirty = false; 11 | if (configuration !== undefined) { 12 | this.setInputConfiguration(el, configuration); 13 | dirty = true; 14 | } 15 | if (value !== undefined) { 16 | this.setInputValue(el, value); 17 | dirty = true; 18 | } 19 | if (dirty) { 20 | this.getCallback(el)(); 21 | this.render(el); 22 | } 23 | } 24 | 25 | const defaultOptions = { 26 | receiveMessage: defaultReceiveMessage, 27 | type: false, 28 | ratePolicy: null 29 | }; 30 | 31 | /** 32 | * Installs a new Shiny input binding based on a React component. 33 | * 34 | * @param {string} selector - jQuery selector that should identify the set of 35 | * container elements within the scope argument of Shiny.InputBinding.find. 36 | * @param {string} name - A name such as 'acme.FooInput' that should uniquely 37 | * identify the component. 38 | * @param {Object} component - React Component, either class or function. 39 | * @param {Object} options - Additional configuration options. Supported 40 | * options are: 41 | * - receiveMessage: Implementation of Shiny.InputBinding to use in place of 42 | * the default. Typically overridden as an optimization to perform 43 | * incremental value updates. 44 | * - type: `false`, a string, or a function. 45 | * - `false` (the default): denotes that the value produced by this input 46 | * should not be intercepted by any handlers registered in R on the 47 | * server using shiny::registerInputHandler(). 48 | * - string: denotes the input's *type* and should correspond to the 49 | * type parameter of shiny::registerInputHandler(). 50 | * - function: A function called with `this` bound to the InputBinding 51 | * instance and passed a single argument, the input's containing DOM 52 | * element. The function should return either `false` or a string 53 | * corresponding to the type parameter of shiny::registerInputHandler(). 54 | * - ratePolicy: A rate policy object as defined in the documentation for 55 | * getRatePolicy(): https://shiny.rstudio.com/articles/building-inputs.html 56 | * A rate policy object has two members: 57 | * - `policy`: Valid values are the strings "direct", "debounce", and 58 | * "throttle". "direct" means that all events are sent immediately. 59 | * - `delay`: Number indicating the number of milliseconds that should be 60 | * used when debouncing or throttling. Has no effect if the policy is 61 | * direct. 62 | * The specified rate policy is only applied when `true` is passed as the 63 | * second argument to the `setValue` function passed as a prop to the 64 | * input component. 65 | * 66 | */ 67 | export function reactShinyInput(selector, 68 | name, 69 | component, 70 | options) { 71 | options = Object.assign({}, defaultOptions, options); 72 | Shiny.inputBindings.register(new class extends Shiny.InputBinding { 73 | 74 | /* 75 | * Methods override those in Shiny.InputBinding 76 | */ 77 | 78 | find(scope) { 79 | return $(scope).find(selector); 80 | } 81 | getValue(el) { 82 | return this.getInputValue(el); 83 | } 84 | setValue(el, value, rateLimited = false) { 85 | /* 86 | * We have to check whether $(el).data('callback') is undefined here 87 | * in case shiny::renderUI() is involved. If an input is contained in a 88 | * shiny::uiOutput(), the following strange thing happens occasionally: 89 | * 90 | * 1. setValue() is bound to an el in this.render(), below 91 | * 2. An event that will call setValue() is enqueued 92 | * 3. While the event is still enqueued, el is unbound and removed 93 | * from the DOM by the JS code associated with shiny::uiOutput() 94 | * - That code uses jQuery .html() in output_binding_html.js 95 | * - .html() removes el from the DOM and clears ist data and events 96 | * 4. By the time the setValue() bound to the original el is invoked, 97 | * el has been unbound and its data cleared. 98 | * 99 | * Since the original input is gone along with its callback, it 100 | * seems to make the most sense to do nothing. 101 | */ 102 | if ($(el).data('callback') !== undefined) { 103 | this.setInputValue(el, value); 104 | this.getCallback(el)(rateLimited); 105 | this.render(el); 106 | } 107 | } 108 | initialize(el) { 109 | $(el).data('value', JSON.parse($(el).next().text())); 110 | $(el).data('configuration', JSON.parse($(el).next().next().text())); 111 | } 112 | subscribe(el, callback) { 113 | $(el).data('callback', callback); 114 | this.render(el); 115 | } 116 | unsubscribe(el) { 117 | ReactDOM.render(null, el); 118 | } 119 | receiveMessage(el, data) { 120 | options.receiveMessage.call(this, el, data); 121 | } 122 | getType(el) { 123 | if (typeof options.type === 'function') { 124 | return options.type.call(this, el); 125 | } else if (options.type === false || typeof options.type === 'string') { 126 | return options.type; 127 | } else { 128 | throw new Error('options.type must be false, a string, or a function'); 129 | } 130 | } 131 | getRatePolicy() { 132 | return options.ratePolicy; 133 | } 134 | 135 | /* 136 | * Methods not present in Shiny.InputBinding but accessible to users 137 | * through `this` in receiveMessage 138 | */ 139 | 140 | getInputValue(el) { 141 | return $(el).data('value'); 142 | } 143 | setInputValue(el, value) { 144 | $(el).data('value', value); 145 | } 146 | getInputConfiguration(el) { 147 | return $(el).data('configuration'); 148 | } 149 | setInputConfiguration(el, configuration) { 150 | $(el).data('configuration', configuration); 151 | } 152 | getCallback(el) { 153 | return $(el).data('callback'); 154 | } 155 | render(el) { 156 | const element = React.createElement(component, { 157 | configuration: this.getInputConfiguration(el), 158 | value: this.getValue(el), 159 | setValue: this.setValue.bind(this, el), 160 | el: el 161 | }); 162 | ReactDOM.render(element, el); 163 | } 164 | }, name); 165 | } 166 | 167 | -------------------------------------------------------------------------------- /srcjs/react-tools.js: -------------------------------------------------------------------------------- 1 | import { reactWidget, hydrate } from './widget'; 2 | import { reactShinyInput } from './input'; 3 | 4 | export { 5 | reactShinyInput, 6 | reactWidget, 7 | hydrate 8 | }; 9 | -------------------------------------------------------------------------------- /srcjs/widget.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Recursively transforms tag, a JSON representation of an instance of a 3 | * React component and its children, into a React element suitable for 4 | * passing to ReactDOM.render. 5 | * @param {Object} components 6 | * @param {Object} tag 7 | */ 8 | export function hydrate(components, tag) { 9 | if (typeof tag === 'string') return tag; 10 | if (tag.name[0] === tag.name[0].toUpperCase() 11 | && !components.hasOwnProperty(tag.name)) { 12 | throw new Error("Unknown component: " + tag.name); 13 | } 14 | // thanks https://github.com/stla 15 | // https://github.com/react-R/reactR/issues/61 16 | // attribs that are slots will likely contain tags that also need hydration 17 | // convert any attribs that contain object that matches tag structure 18 | for(let attrib in tag.attribs) { 19 | if(isTag(tag.attribs[attrib])) { 20 | tag.attribs[attrib] = hydrate(components, tag.attribs[attrib]); 21 | } 22 | } 23 | var elem = components.hasOwnProperty(tag.name) ? components[tag.name] : tag.name, 24 | args = [elem, tag.attribs]; 25 | for (var i = 0; i < tag.children.length; i++) { 26 | args.push(hydrate(components, tag.children[i])); 27 | } 28 | return React.createElement.apply(React, args); 29 | } 30 | 31 | export const defaultOptions = { 32 | // The name of the property on the root tag to use for the width, if 33 | // it's updated. 34 | widthProperty: "width", 35 | // The name of the property on the root tag to use for the height, if 36 | // it's updated. 37 | heightProperty: "height", 38 | // Whether or not to append the string 'px' to the width and height 39 | // properties when they change. 40 | appendPx: false, 41 | // Whether or not to dynamically update the width and height properties 42 | // of the last known tag when the computed width and height change in 43 | // the browser. 44 | renderOnResize: false 45 | }; 46 | 47 | export function mergeOptions(options) { 48 | var merged = {}; 49 | for (var k in defaultOptions) { 50 | merged[k] = defaultOptions[k]; 51 | } 52 | for (var k in options) { 53 | if (!defaultOptions.hasOwnProperty(k)) { 54 | throw new Error("Unrecognized option: " + k); 55 | } 56 | merged[k] = options[k]; 57 | } 58 | return merged; 59 | } 60 | 61 | export function formatDimension(dim, options) { 62 | if (options.appendPx) { 63 | return dim + 'px'; 64 | } else { 65 | return dim; 66 | } 67 | } 68 | 69 | export function isTag(value) { 70 | return (typeof value === 'object') 71 | && value.hasOwnProperty('name') 72 | && value.hasOwnProperty('attribs') 73 | && value.hasOwnProperty('children'); 74 | } 75 | 76 | /** 77 | * Creates an HTMLWidget that is updated by rendering a React component. 78 | * React component constructors are made available by specifying them by 79 | * name in the components object. 80 | * @param {string} name 81 | * @param {string} type 82 | * @param {Object} components 83 | * @param {Object} options 84 | */ 85 | export function reactWidget(name, type, components, options) { 86 | var actualOptions = mergeOptions(options); 87 | window.HTMLWidgets.widget({ 88 | name: name, 89 | type: type, 90 | factory: function (el, width, height) { 91 | var lastValue, 92 | instance = {}, 93 | renderValue = (function (value) { 94 | if (actualOptions.renderOnResize) { 95 | // value.tag might be a primitive string, in which 96 | // case there is no attribs property. 97 | if (typeof value.tag === 'object') { 98 | value.tag.attribs[actualOptions["widthProperty"]] = formatDimension(width); 99 | value.tag.attribs[actualOptions["heightProperty"]] = formatDimension(height); 100 | } 101 | lastValue = value; 102 | } 103 | // with functional stateless components this will be null 104 | // see https://reactjs.org/docs/react-dom.html#render for more details 105 | this.instance.component = ReactDOM.render(hydrate(components, value.tag), el); 106 | }); 107 | return { 108 | instance: instance, 109 | renderValue: renderValue, 110 | resize: function (newWidth, newHeight) { 111 | if (actualOptions.renderOnResize) { 112 | width = newWidth; 113 | height = newHeight; 114 | renderValue(lastValue); 115 | } 116 | } 117 | }; 118 | } 119 | }) 120 | } 121 | 122 | -------------------------------------------------------------------------------- /vignettes/input_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/vignettes/input_app.jpg -------------------------------------------------------------------------------- /vignettes/input_sketchpicker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/vignettes/input_sketchpicker.jpg -------------------------------------------------------------------------------- /vignettes/input_sketchpicker.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/vignettes/input_sketchpicker.mp4 -------------------------------------------------------------------------------- /vignettes/intro_reactR.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Intro to reactR" 3 | author: "Kent Russell" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Intro to reactR} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ## Why reactR? 13 | 14 | [`react`](https://reactjs.org/) has become incredibly popular, and the ecosystem around `react` is robust. `reactR` aims to allow `R` users to more easily incorporate `react` and `JSX`. 15 | 16 | ## Install 17 | 18 | ``` 19 | install.packages("reactR") 20 | 21 | # for the latest development version 22 | # install from Github 23 | # devtools::install_github("timelyportfolio/reactR") 24 | ``` 25 | 26 | ## Quick Example 27 | 28 | Let's use `react` to render a simple `h1` HTML element below. 29 | 30 |
    31 | 32 | ```{r} 33 | library(reactR) 34 | library(htmltools) 35 | 36 | attachDependencies( 37 | tags$script( 38 | " 39 | ReactDOM.render( 40 | React.createElement( 41 | 'h1', 42 | null, 43 | 'Powered by React' 44 | ), 45 | document.getElementById('react-heading-here') 46 | ) 47 | " 48 | ), 49 | html_dependency_react() 50 | ) 51 | ``` 52 | 53 | ## Blog Post 54 | 55 | For more on how we can use R and React, see the blog post [React in R](https://www.jsinr.me/2017/11/19/react-in-r/). Also, there are many more examples in the Github repo at [inst/examples](https://github.com/react-R/reactR/tree/master/inst/examples). 56 | 57 | ## Using JSX 58 | 59 | [`JSX`](https://reactjs.org/docs/jsx-in-depth.html) helps ease some of the burden caused by `React.createElement`. `reactR` provides a `babel_transform()` function to use `JSX`. Hopefully, in the future, we can convince RStudio to modify `htmltools` to work directly with `JSX` (see [issue](https://github.com/rstudio/htmltools/pull/72)). 60 | -------------------------------------------------------------------------------- /vignettes/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 25 | 30 | 35 | 36 | 45 | 50 | 55 | 56 | 66 | 67 | 69 | 70 | 72 | image/svg+xml 73 | 75 | 76 | 77 | 78 | 79 | 82 | 85 | 89 | 93 | 94 | 98 | 102 | 106 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /vignettes/widget_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/vignettes/widget_app.jpg -------------------------------------------------------------------------------- /vignettes/widget_app_improved.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-R/reactR/808b21f4f2e5c374cb8ec910f8e2cc27f6b40e1b/vignettes/widget_app_improved.jpg -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { resolve, join } from 'path'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | define: { 'process.env.NODE_ENV': '"production"' }, 6 | build: { 7 | outDir: join(__dirname, "inst/www/react-tools/"), 8 | lib: { 9 | // Could also be a dictionary or array of multiple entry points 10 | entry: resolve(__dirname, 'srcjs/react-tools.js'), 11 | name: 'reactR', 12 | fileName: () => 'react-tools.js', 13 | formats: ['umd'], 14 | }, 15 | rollupOptions: { 16 | external: ['react', 'react-dom', 'jquery', 'shiny'], 17 | output: { 18 | globals: { 19 | 'react': 'React', 20 | 'react-dom': 'ReactDOM', 21 | 'jquery': '$', 22 | 'shiny': 'Shiny' 23 | }, 24 | }, 25 | }, 26 | }, 27 | }); 28 | --------------------------------------------------------------------------------