diff --git a/CHANGELOG.md b/CHANGELOG.md index 084a665..2c9c23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,17 +5,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] + +### Added +- Added a `tag` option to change the tag used to render the component (default is `div`) + ## 0.2.0 - 2017-03-20 + ### Added - support for Turbolinks 5, Turbolinks 2.4 and PJAX. Components will be mounted and unmounted when Turbolinks-specific events occur. Also, the integration works with Turbolinks 5 cache. - New `WebpackerReact.setup({Component1, Component2, ...})` initialization API. The old API couldn't properly detect the components' names, thus user is required to provide the names in the configuration object's keys. + ### Removed - `WebpackerReact.register(Component)` has been dropped in favor of `WebpackerReact.setup({Component})` + + ## 0.1.0 - 2017-02-23 + ### Added - First released version - render React components from views using the `react_component` helper - render React components from controllers using `render react_component: 'name'` (#1 by @daninfpj) - basic Hot Module Remplacement (#7 by @mfazekas) -[Unreleased]: https://github.com/renchap/webpacker-react/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/renchap/webpacker-react/compare/v0.2.0...HEAD diff --git a/README.md b/README.md index f51d452..9efd1e8 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,19 @@ Now you can render React components from your views or your controllers. ### Rendering from a view -Use the `react_component` helper: +Use the `react_component` helper. The first argument is your component's name, the second one is the `props`: ```erb <%= react_component('Hello', name: 'React') %> ``` +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`: + +```erb +<%= react_component('Hello', { name: 'React' }, tag: :span, class: 'my-custom-component') %> +# This will render +``` + ### Rendering from a controller ```rb @@ -86,7 +93,13 @@ class PageController < ApplicationController end ``` -You can pass any of the usual arguments to render in this call: `layout`, `status`, `content_type`, etc. +You can use the `tag_options` argument to change the generated HTML, similar to the `react_component` method above: + +```rb +render react_component: 'Hello', props: { name: 'React' }, tag_options: { tag: :span, class: 'my-custom-component' } +``` + +You can also pass any of the usual arguments to `render` in this call: `layout`, `status`, `content_type`, etc. *Note: you need to have [Webpack process your code](https://github.com/rails/webpacker#binstubs) before it is available to the browser, either by manually running `./bin/webpack` or having the `./bin/webpack-watcher` process running.* diff --git a/lib/webpacker/react/component.rb b/lib/webpacker/react/component.rb index 6f1b809..9d8a380 100644 --- a/lib/webpacker/react/component.rb +++ b/lib/webpacker/react/component.rb @@ -11,8 +11,10 @@ def initialize(name) end def render(props = {}, options = {}) + tag = options.delete(:tag) || :div data = { data: { "react-class" => @name, "react-props" => props.to_json } } - content_tag(:div, nil, options.deep_merge(data)) + + content_tag(tag, nil, options.deep_merge(data)) end end end diff --git a/lib/webpacker/react/railtie.rb b/lib/webpacker/react/railtie.rb index 0d390c4..6b25d15 100644 --- a/lib/webpacker/react/railtie.rb +++ b/lib/webpacker/react/railtie.rb @@ -12,7 +12,8 @@ class Engine < ::Rails::Engine initializer :webpacker_react_renderer, group: :all do |_app| ActionController::Renderers.add :react_component do |component_name, options| props = options.fetch(:props, {}) - html = Webpacker::React::Component.new(component_name).render(props) + tag_options = options.fetch(:tag_options, {}) + html = Webpacker::React::Component.new(component_name).render(props, tag_options) render_options = options.merge(inline: html) render(render_options) end diff --git a/test/example_app/app/controllers/custom_tag_controller.rb b/test/example_app/app/controllers/custom_tag_controller.rb new file mode 100644 index 0000000..0778aeb --- /dev/null +++ b/test/example_app/app/controllers/custom_tag_controller.rb @@ -0,0 +1,8 @@ +class CustomTagController < ApplicationController + def view_component + end + + def controller_component + render react_component: "HelloReact", props: { name: "a component rendered from a controller in a span" }, tag_options: { tag: :span } + end +end diff --git a/test/example_app/app/views/custom_tag/view_component.html.erb b/test/example_app/app/views/custom_tag/view_component.html.erb new file mode 100644 index 0000000..3265e4d --- /dev/null +++ b/test/example_app/app/views/custom_tag/view_component.html.erb @@ -0,0 +1 @@ +<%= react_component('HelloReact', { name: 'a component rendered from a view in a span' }, tag: :span) %> diff --git a/test/example_app/config/routes.rb b/test/example_app/config/routes.rb index e36a480..750a4e4 100644 --- a/test/example_app/config/routes.rb +++ b/test/example_app/config/routes.rb @@ -9,5 +9,8 @@ get "/two_packs/view_all", to: "two_packs#view_all" + get "/custom_tag_view", to: "custom_tag#view_component" + get "/custom_tag_controller", to: "custom_tag#controller_component" + root to: "pages#view_component" end diff --git a/test/integration/custom_tag_test.rb b/test/integration/custom_tag_test.rb new file mode 100644 index 0000000..3b658ae --- /dev/null +++ b/test/integration/custom_tag_test.rb @@ -0,0 +1,17 @@ +require "test_helper" + +class CustomTagTest < ActionDispatch::IntegrationTest + test "renders from a view with a custom tag" do + require_js + + visit "/custom_tag_view" + assert_selector "span[data-react-class]", text: "Hello, I am a component rendered from a view in a span!" + end + + test "renders from a controller with a custom tag" do + require_js + + visit "/custom_tag_controller" + assert_selector "span[data-react-class]", text: "Hello, I am a component rendered from a controller in a span!" + end +end diff --git a/test/integration/renderer_test.rb b/test/integration/renderer_test.rb index a24b348..8fd4635 100644 --- a/test/integration/renderer_test.rb +++ b/test/integration/renderer_test.rb @@ -30,10 +30,4 @@ def url_prefix assert page.has_content? "component 1" assert page.has_content? "component 2" end - - private - - def require_js - Capybara.current_driver = Capybara.javascript_driver - end end diff --git a/test/integration/renderer_with_two_packs_test.rb b/test/integration/renderer_with_two_packs_test.rb index 85084bc..4c90052 100644 --- a/test/integration/renderer_with_two_packs_test.rb +++ b/test/integration/renderer_with_two_packs_test.rb @@ -15,10 +15,4 @@ class RendererWithTwoPacksTest < ActionDispatch::IntegrationTest assert page.has_content? "Component A" assert page.has_content? "Component B" end - -private - - def require_js - Capybara.current_driver = Capybara.javascript_driver - end end diff --git a/test/test_helper.rb b/test/test_helper.rb index e14caac..720f5e6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -14,4 +14,8 @@ class ActionDispatch::IntegrationTest def teardown Capybara.current_driver = nil end + + def require_js + Capybara.current_driver = Capybara.javascript_driver + end end diff --git a/test/webpacker/react/component_test.rb b/test/webpacker/react/component_test.rb index d32d43b..ebfbcd4 100644 --- a/test/webpacker/react/component_test.rb +++ b/test/webpacker/react/component_test.rb @@ -51,6 +51,18 @@ def test_it_accepts_html_options ) end + def test_it_accepts_tag_option + html = Webpacker::React::Component.new(@component[:name]) + .render( + @component[:props], + tag: "span" + ) + + assert( + html.include?("