react-components-rails 1.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/PULL_REQUEST_TEMPLATE +9 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +119 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +41 -0
- data/LICENSE +21 -0
- data/README.md +128 -0
- data/lib/component.rb +21 -0
- data/lib/helpers.rb +9 -0
- data/lib/railtie.rb +27 -0
- data/package.json +45 -0
- data/react-components-rails.gemspec +31 -0
- data/src/index.ts +90 -0
- data/src/ujs.ts +85 -0
- data/tsconfig.json +101 -0
- data/yarn.lock +5101 -0
- metadata +88 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7e8b48934b25fc73c93eadc46d1fb4386a9289f40d1441be9a4a3f3cdb1cfb5d
|
|
4
|
+
data.tar.gz: 284e9e9ec4e81e4659f2a34385b3e7ab0df67ef258b60359da0b1a01e88eea1c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 422e20effaf3f3b830a7f68fb771e8b61a7f42450cc80a4d491533be07995be85c4f11e4c37fea7643aaea7da857136e6909d725a5bf53d4dfe308a5a8bc42a4
|
|
7
|
+
data.tar.gz: 2487723877f13ea41e3652fb38355935f237ea9b59f4285a7c8583485e1eb933e622c19b0a54863472a7bb39d704e2c015558539e4719f2a4c607071f9233269
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Fixes # .
|
|
2
|
+
|
|
3
|
+
Changes:
|
|
4
|
+
|
|
5
|
+
Please ensure that:
|
|
6
|
+
- [ ] Changelog is updated if not a minor patch
|
|
7
|
+
- [ ] Ruby linting is ok: `rubocop` is all green
|
|
8
|
+
- [ ] Javascript linting is ok: `cd javascript/webpacker_react-npm-module/ && yarn lint` is all green
|
|
9
|
+
- [ ] [Tests](https://github.com/renchap/webpacker-react#testing) are all green
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.3
|
|
3
|
+
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
|
|
4
|
+
# to ignore them, so only the ones explicitly set in this file are enabled.
|
|
5
|
+
DisabledByDefault: true
|
|
6
|
+
Exclude:
|
|
7
|
+
- '**/node_modules/**/*'
|
|
8
|
+
- '**/vendor/**/*'
|
|
9
|
+
|
|
10
|
+
# Prefer &&/|| over and/or.
|
|
11
|
+
Style/AndOr:
|
|
12
|
+
Enabled: true
|
|
13
|
+
|
|
14
|
+
# Do not use braces for hash literals when they are the last argument of a
|
|
15
|
+
# method call.
|
|
16
|
+
Style/BracesAroundHashParameters:
|
|
17
|
+
Enabled: true
|
|
18
|
+
|
|
19
|
+
# Align `when` with `case`.
|
|
20
|
+
Layout/CaseIndentation:
|
|
21
|
+
Enabled: true
|
|
22
|
+
|
|
23
|
+
# Align comments with method definitions.
|
|
24
|
+
Layout/CommentIndentation:
|
|
25
|
+
Enabled: true
|
|
26
|
+
|
|
27
|
+
# No extra empty lines.
|
|
28
|
+
Layout/EmptyLines:
|
|
29
|
+
Enabled: true
|
|
30
|
+
|
|
31
|
+
# In a regular class definition, no empty lines around the body.
|
|
32
|
+
Layout/EmptyLinesAroundClassBody:
|
|
33
|
+
Enabled: true
|
|
34
|
+
|
|
35
|
+
# In a regular module definition, no empty lines around the body.
|
|
36
|
+
Layout/EmptyLinesAroundModuleBody:
|
|
37
|
+
Enabled: true
|
|
38
|
+
|
|
39
|
+
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
|
|
40
|
+
Style/HashSyntax:
|
|
41
|
+
Enabled: true
|
|
42
|
+
|
|
43
|
+
# Method definitions after `private` or `protected` isolated calls need one
|
|
44
|
+
# extra level of indentation.
|
|
45
|
+
Layout/IndentationConsistency:
|
|
46
|
+
Enabled: true
|
|
47
|
+
EnforcedStyle: indented_internal_methods
|
|
48
|
+
|
|
49
|
+
# Two spaces, no tabs (for indentation).
|
|
50
|
+
Layout/IndentationWidth:
|
|
51
|
+
Enabled: true
|
|
52
|
+
|
|
53
|
+
Layout/SpaceAfterColon:
|
|
54
|
+
Enabled: true
|
|
55
|
+
|
|
56
|
+
Layout/SpaceAfterComma:
|
|
57
|
+
Enabled: true
|
|
58
|
+
|
|
59
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
60
|
+
Enabled: true
|
|
61
|
+
|
|
62
|
+
Layout/SpaceAroundKeyword:
|
|
63
|
+
Enabled: true
|
|
64
|
+
|
|
65
|
+
Layout/SpaceAroundOperators:
|
|
66
|
+
Enabled: true
|
|
67
|
+
|
|
68
|
+
Layout/SpaceBeforeFirstArg:
|
|
69
|
+
Enabled: true
|
|
70
|
+
|
|
71
|
+
# Defining a method with parameters needs parentheses.
|
|
72
|
+
Style/MethodDefParentheses:
|
|
73
|
+
Enabled: true
|
|
74
|
+
|
|
75
|
+
# Use `foo {}` not `foo{}`.
|
|
76
|
+
Layout/SpaceBeforeBlockBraces:
|
|
77
|
+
Enabled: true
|
|
78
|
+
|
|
79
|
+
# Use `foo { bar }` not `foo {bar}`.
|
|
80
|
+
Layout/SpaceInsideBlockBraces:
|
|
81
|
+
Enabled: true
|
|
82
|
+
|
|
83
|
+
# Use `{ a: 1 }` not `{a:1}`.
|
|
84
|
+
Layout/SpaceInsideHashLiteralBraces:
|
|
85
|
+
Enabled: true
|
|
86
|
+
|
|
87
|
+
Layout/SpaceInsideParens:
|
|
88
|
+
Enabled: true
|
|
89
|
+
|
|
90
|
+
# Check quotes usage according to lint rule below.
|
|
91
|
+
Style/StringLiterals:
|
|
92
|
+
Enabled: true
|
|
93
|
+
EnforcedStyle: double_quotes
|
|
94
|
+
|
|
95
|
+
# Detect hard tabs, no hard tabs.
|
|
96
|
+
Layout/Tab:
|
|
97
|
+
Enabled: true
|
|
98
|
+
|
|
99
|
+
# Blank lines should not have any spaces.
|
|
100
|
+
Layout/TrailingBlankLines:
|
|
101
|
+
Enabled: true
|
|
102
|
+
|
|
103
|
+
# No trailing whitespace.
|
|
104
|
+
Layout/TrailingWhitespace:
|
|
105
|
+
Enabled: true
|
|
106
|
+
|
|
107
|
+
# Use quotes for string literals when they are enough.
|
|
108
|
+
Style/UnneededPercentQ:
|
|
109
|
+
Enabled: true
|
|
110
|
+
|
|
111
|
+
# Align `end` with the matching keyword or starting expression except for
|
|
112
|
+
# assignments, where it should be aligned with the LHS.
|
|
113
|
+
Lint/EndAlignment:
|
|
114
|
+
Enabled: true
|
|
115
|
+
EnforcedStyleAlignWith: variable
|
|
116
|
+
|
|
117
|
+
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
|
118
|
+
Lint/RequireParentheses:
|
|
119
|
+
Enabled: true
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
## Our Standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
|
15
|
+
include:
|
|
16
|
+
|
|
17
|
+
* Using welcoming and inclusive language
|
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
|
19
|
+
* Gracefully accepting constructive criticism
|
|
20
|
+
* Focusing on what is best for the community
|
|
21
|
+
* Showing empathy towards other community members
|
|
22
|
+
|
|
23
|
+
Examples of unacceptable behavior by participants include:
|
|
24
|
+
|
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
+
advances
|
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
+
* Public or private harassment
|
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
|
30
|
+
address, without explicit permission
|
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
+
professional setting
|
|
33
|
+
|
|
34
|
+
## Our Responsibilities
|
|
35
|
+
|
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
+
response to any instances of unacceptable behavior.
|
|
39
|
+
|
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
+
threatening, offensive, or harmful.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
+
when an individual is representing the project or its community. Examples of
|
|
50
|
+
representing a project or community include using an official project e-mail
|
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
|
53
|
+
further defined and clarified by project maintainers.
|
|
54
|
+
|
|
55
|
+
## Enforcement
|
|
56
|
+
|
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
+
reported by contacting the project maintainer at renchap@gmail.com. All
|
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
|
63
|
+
|
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
+
members of the project's leadership.
|
|
67
|
+
|
|
68
|
+
## Attribution
|
|
69
|
+
|
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
|
72
|
+
|
|
73
|
+
[homepage]: http://contributor-covenant.org
|
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
react-components-rails (1.0.0.beta1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
ast (2.4.2)
|
|
10
|
+
parallel (1.21.0)
|
|
11
|
+
parser (3.1.1.0)
|
|
12
|
+
ast (~> 2.4.1)
|
|
13
|
+
rainbow (3.1.1)
|
|
14
|
+
rake (13.0.6)
|
|
15
|
+
regexp_parser (2.2.1)
|
|
16
|
+
rexml (3.2.5)
|
|
17
|
+
rubocop (1.25.1)
|
|
18
|
+
parallel (~> 1.10)
|
|
19
|
+
parser (>= 3.1.0.0)
|
|
20
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
21
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
22
|
+
rexml
|
|
23
|
+
rubocop-ast (>= 1.15.1, < 2.0)
|
|
24
|
+
ruby-progressbar (~> 1.7)
|
|
25
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
26
|
+
rubocop-ast (1.16.0)
|
|
27
|
+
parser (>= 3.1.1.0)
|
|
28
|
+
ruby-progressbar (1.11.0)
|
|
29
|
+
unicode-display_width (2.1.0)
|
|
30
|
+
|
|
31
|
+
PLATFORMS
|
|
32
|
+
x86_64-darwin-21
|
|
33
|
+
|
|
34
|
+
DEPENDENCIES
|
|
35
|
+
bundler (~> 2.3)
|
|
36
|
+
rake (~> 13.0)
|
|
37
|
+
react-components-rails!
|
|
38
|
+
rubocop
|
|
39
|
+
|
|
40
|
+
BUNDLED WITH
|
|
41
|
+
2.3.7
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Renaud Chaput
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# React-Components-Rails
|
|
2
|
+
|
|
3
|
+
_**Note:** This project was formerly known as `webpacker-rails`. Following Webpacker's deprecation, it has been renamed and rewritten to no longer rely on Webpacker. Documentation for the latest `webpacker-rails` release (1.0.0-beta.1) is [available here](https://github.com/renchap/webpacker-react/tree/v1.0.0-beta.1)._
|
|
4
|
+
|
|
5
|
+
React-Components-Rails makes it easy to use [React](https://reactjs.org/) with your Rails applications. It provides Controller and View helpers to render React Components on your application, and does not case about the way you ship your Javascript
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
First, you need to add this gem to your Rails app Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'react-components-rails', "~> 1.0.0.beta.1"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Once done, run `bundle` to install the gem.
|
|
16
|
+
|
|
17
|
+
Then you need to update your `package.json` file to include the `react-components-rails` Javascript module:
|
|
18
|
+
|
|
19
|
+
`yarn add react-components-rails`
|
|
20
|
+
|
|
21
|
+
You are now all set!
|
|
22
|
+
|
|
23
|
+
### Note about versions
|
|
24
|
+
|
|
25
|
+
React-Components-Rails contains two parts: a Javascript module and a Ruby gem. Both of those components respect [semantic versioning](http://semver.org). **When upgrading the gem, you need to upgrade the NPM module to the same minor version**. New patch versions can be released for each of the two independently, so it is ok to have the NPM module at version `A.X.Y` and the gem at version `A.X.Z`, but you should never have a different `A` or `X`.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
The first step is to register your root components (those you want to load from your HTML).
|
|
30
|
+
In your app entry file, import your components as well as `react-components-rails` and register them. Considering you have a component in `app/javascript/components/hello.js`:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import Hello from "components/hello"
|
|
34
|
+
import ReactComponentsRails from "react-components-rails"
|
|
35
|
+
|
|
36
|
+
ReactComponentsRails.setup({ Hello }) // ES6 shorthand for {Hello: Hello}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Rendering from a view
|
|
40
|
+
|
|
41
|
+
Use the `react_component` helper. The first argument is your component's name, the second one is the `props`:
|
|
42
|
+
|
|
43
|
+
```erb
|
|
44
|
+
<%= react_component('Hello', name: 'React') %>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
You can pass a `tag` argument to render the React component in another tag than the default `div`. All other arguments will be passed to `content_tag`:
|
|
48
|
+
|
|
49
|
+
```erb
|
|
50
|
+
<%= react_component('Hello', { name: 'React' }, tag: :span, class: 'my-custom-component') %>
|
|
51
|
+
# This will render <span class="my-custom-component" data-react-class="Hello" data-react-props="..."></span>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Rendering from a controller
|
|
55
|
+
|
|
56
|
+
```rb
|
|
57
|
+
class PageController < ApplicationController
|
|
58
|
+
def main
|
|
59
|
+
render react_component: 'Hello', props: { name: 'React' }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
You can use the `tag_options` argument to change the generated HTML, similar to the `react_component` method above:
|
|
65
|
+
|
|
66
|
+
```rb
|
|
67
|
+
render react_component: 'Hello', props: { name: 'React' }, tag_options: { tag: :span, class: 'my-custom-component' }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
You can also pass any of the usual arguments to `render` in this call: `layout`, `status`, `content_type`, etc.
|
|
71
|
+
|
|
72
|
+
### Hot Module Replacement
|
|
73
|
+
|
|
74
|
+
It should be supported out of the box, if supported by your Javascript stack. Please refer to your Javascript compiler/bundler documentation to do so.
|
|
75
|
+
|
|
76
|
+
<!--
|
|
77
|
+
## Development
|
|
78
|
+
|
|
79
|
+
To work on this gem locally, you first need to clone and setup [the example application](https://github.com/renchap/webpacker-react-example).
|
|
80
|
+
|
|
81
|
+
Then you need to change the example app Gemfile to point to your local repository and run bundle afterwise:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
gem 'webpacker-react', path: '~/code/webpacker-react/'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Finally, you need to tell Yarn to use your local copy of the NPM module in this application, using [`yarn link`](https://yarnpkg.com/en/docs/cli/link):
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
$ cd ~/code/webpacker-react/javascript/webpacker_react-npm-module/
|
|
91
|
+
$ yarn
|
|
92
|
+
$ cd dist/
|
|
93
|
+
$ yarn # compiles the code from src/ to dist/
|
|
94
|
+
$ yarn link
|
|
95
|
+
success Registered "webpacker-react".
|
|
96
|
+
info You can now run `yarn link "webpacker-react"` in the projects where you want to use this module and it will be used instead.
|
|
97
|
+
$ cd ~/code/webpacker-react-example/
|
|
98
|
+
$ yarn link webpacker-react
|
|
99
|
+
success Registered "webpacker-react".
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
After launching `./bin/webpack-watcher` and `./bin/rails server` in your example app directory, you can now change the Ruby or Javascript code in your local `webpacker-react` repository, and test it immediately using the example app.
|
|
103
|
+
|
|
104
|
+
## Testing
|
|
105
|
+
|
|
106
|
+
If you changed the local javascript package, first ensure it is build (see above).
|
|
107
|
+
|
|
108
|
+
To run the test suite:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
$ rake test
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If you change the javascript code, please ensure there are no style errors before committing:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
$ cd javascript/webpacker_react-npm-module/
|
|
118
|
+
$ yarn lint
|
|
119
|
+
``` -->
|
|
120
|
+
|
|
121
|
+
## Contributing
|
|
122
|
+
|
|
123
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/renchap/webpacker-react.
|
|
124
|
+
Please feel free to open issues about your needs and features you would like to be added.
|
|
125
|
+
|
|
126
|
+
### Thanks
|
|
127
|
+
|
|
128
|
+
This gem has been inspired by the awesome work on [react-rails](https://github.com/reactjs/react-rails) and [react_on_rails](https://github.com/shakacode/react_on_rails/). Many thanks to their authors!
|
data/lib/component.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ReactComponentsRails
|
|
4
|
+
class Component
|
|
5
|
+
include ActionView::Helpers::TagHelper
|
|
6
|
+
include ActionView::Helpers::TextHelper
|
|
7
|
+
|
|
8
|
+
attr_accessor :name
|
|
9
|
+
|
|
10
|
+
def initialize(name)
|
|
11
|
+
@name = name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render(props = {}, options = {})
|
|
15
|
+
tag = options.delete(:tag) || :div
|
|
16
|
+
data = { data: { "react-class" => @name, "react-props" => props.to_json } }
|
|
17
|
+
|
|
18
|
+
content_tag(tag, nil, options.deep_merge(data))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/helpers.rb
ADDED
data/lib/railtie.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/railtie"
|
|
4
|
+
|
|
5
|
+
module ReactComponentsRails
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
initializer :react_components do
|
|
8
|
+
ActiveSupport.on_load(:action_controller) do
|
|
9
|
+
ActionController::Base.helper ::ReactComponentsRails::Helpers
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
ActiveSupport.on_load :action_view do
|
|
13
|
+
include ::ReactComponentsRails::Helpers
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
initializer :react_components_rails_renderer, group: :all do |_app|
|
|
18
|
+
ActionController::Renderers.add :react_component do |component_name, options|
|
|
19
|
+
props = options.fetch(:props, {})
|
|
20
|
+
tag_options = options.fetch(:tag_options, {})
|
|
21
|
+
html = ReactComponentsRails::Component.new(component_name).render(props, tag_options)
|
|
22
|
+
render_options = options.merge(inline: html)
|
|
23
|
+
render(render_options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-components-rails",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"homepage": "https://github.com/renchap/react-components-rails",
|
|
5
|
+
"repository": "renchap/react-components-rails",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Renaud Chaput",
|
|
8
|
+
"email": "renchap@gmail.com"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"source": "src/index.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
"require": "./dist/react-components-rails.cjs",
|
|
15
|
+
"default": "./dist/react-components-rails.modern.js"
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/react-components-rails.cjs",
|
|
18
|
+
"module": "./dist/react-components-rails.module.js",
|
|
19
|
+
"unpkg": "./dist/react-components-rails.umd.js",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "microbundle",
|
|
22
|
+
"dev": "microbundle watch"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@types/lodash": "^4.14.179",
|
|
26
|
+
"lodash": "^4.17.21"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": ">= 0.14",
|
|
30
|
+
"react-dom": ">= 0.14"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/react": "^17.0.39",
|
|
34
|
+
"@types/react-dom": "^17.0.11",
|
|
35
|
+
"microbundle": "^0.14.2",
|
|
36
|
+
"prettier": "^2.5.1",
|
|
37
|
+
"react": "^17.0.2",
|
|
38
|
+
"react-dom": "^17.0.2",
|
|
39
|
+
"typescript": "^4.5.5"
|
|
40
|
+
},
|
|
41
|
+
"packageManager": "yarn@3.2.0",
|
|
42
|
+
"prettier": {
|
|
43
|
+
"semi": false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "react-components-rails"
|
|
8
|
+
spec.licenses = ["MIT"]
|
|
9
|
+
spec.version = "1.0.0.beta1"
|
|
10
|
+
spec.authors = ["Renaud Chaput"]
|
|
11
|
+
spec.email = ["renchap@gmail.com"]
|
|
12
|
+
|
|
13
|
+
spec.summary = "Provides Rails helpers to render React Components"
|
|
14
|
+
# spec.description = %q{TODO: Write a longer description or delete this line.}
|
|
15
|
+
spec.homepage = "https://github.com/renchap/webpacker-react"
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
|
19
|
+
end
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
|
+
spec.require_paths = ["lib"]
|
|
23
|
+
|
|
24
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
25
|
+
|
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.3"
|
|
27
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
28
|
+
# spec.add_development_dependency "minitest", "~> 5.0"
|
|
29
|
+
# spec.add_development_dependency "capybara"
|
|
30
|
+
# spec.add_development_dependency "selenium-webdriver"
|
|
31
|
+
end
|
data/src/index.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import ReactDOM from "react-dom"
|
|
3
|
+
import intersection from "lodash/intersection"
|
|
4
|
+
import keys from "lodash/keys"
|
|
5
|
+
import assign from "lodash/assign"
|
|
6
|
+
import omit from "lodash/omit"
|
|
7
|
+
// import ujs from './ujs'
|
|
8
|
+
|
|
9
|
+
const CLASS_ATTRIBUTE_NAME = "data-react-class"
|
|
10
|
+
const PROPS_ATTRIBUTE_NAME = "data-react-props"
|
|
11
|
+
|
|
12
|
+
declare global {
|
|
13
|
+
interface Window {
|
|
14
|
+
ReactComponentsRails: typeof ReactComponentsRails
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ReactComponentsRails = {
|
|
19
|
+
registeredComponents: {} as { [name: string]: React.ComponentType },
|
|
20
|
+
|
|
21
|
+
render(node: Element, component: React.ComponentType) {
|
|
22
|
+
const propsJson = node.getAttribute(PROPS_ATTRIBUTE_NAME)
|
|
23
|
+
const props = propsJson && JSON.parse(propsJson)
|
|
24
|
+
|
|
25
|
+
const reactElement = React.createElement(component, props)
|
|
26
|
+
|
|
27
|
+
ReactDOM.render(reactElement, node)
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
registerComponents(components: { [name: string]: React.Component }) {
|
|
31
|
+
const collisions = intersection(
|
|
32
|
+
keys(this.registeredComponents),
|
|
33
|
+
keys(components)
|
|
34
|
+
)
|
|
35
|
+
if (collisions.length > 0) {
|
|
36
|
+
console.error(
|
|
37
|
+
`react-components-rails: can not register components. Following components are already registered: ${collisions}`
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
assign(this.registeredComponents, omit(components, collisions))
|
|
42
|
+
return true
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
unmountComponents() {
|
|
46
|
+
const mounted = document.querySelectorAll(`[${CLASS_ATTRIBUTE_NAME}]`)
|
|
47
|
+
for (let i = 0; i < mounted.length; i += 1) {
|
|
48
|
+
ReactDOM.unmountComponentAtNode(mounted[i])
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
mountComponents() {
|
|
53
|
+
const { registeredComponents } = this
|
|
54
|
+
const toMount = document.querySelectorAll(`[${CLASS_ATTRIBUTE_NAME}]`)
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < toMount.length; i += 1) {
|
|
57
|
+
const node = toMount[i]
|
|
58
|
+
const className = node.getAttribute(CLASS_ATTRIBUTE_NAME)
|
|
59
|
+
|
|
60
|
+
if (!className) {
|
|
61
|
+
console.error(
|
|
62
|
+
`react-components-rails: no ${CLASS_ATTRIBUTE_NAME} attribute on element: ${node}`
|
|
63
|
+
)
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const component = registeredComponents[className]
|
|
68
|
+
|
|
69
|
+
if (component) {
|
|
70
|
+
if (node.innerHTML.length === 0) this.render(node, component)
|
|
71
|
+
} else {
|
|
72
|
+
console.error(
|
|
73
|
+
`react-components-rails: can not render a component that has not been registered: ${className}`
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
setup(components = {}) {
|
|
80
|
+
if (typeof window.ReactComponentsRails === "undefined") {
|
|
81
|
+
window.ReactComponentsRails = this
|
|
82
|
+
// ujs.setup(this.mountComponents.bind(this), this.unmountComponents.bind(this))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
window.ReactComponentsRails.registerComponents(components)
|
|
86
|
+
window.ReactComponentsRails.mountComponents()
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default ReactComponentsRails
|