hyper-react 0.11.0 → 0.12.0

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +11 -0
  4. data/Appraisals +10 -0
  5. data/CHANGELOG.md +31 -0
  6. data/Gemfile +2 -0
  7. data/README.md +7 -0
  8. data/gemfiles/opal_0.10_react_13.gemfile +4 -0
  9. data/gemfiles/opal_0.10_react_14.gemfile +4 -0
  10. data/gemfiles/opal_0.10_react_15.gemfile +4 -0
  11. data/gemfiles/opal_0.8_react_13.gemfile +4 -0
  12. data/gemfiles/opal_0.8_react_14.gemfile +4 -0
  13. data/gemfiles/opal_0.8_react_15.gemfile +4 -0
  14. data/gemfiles/opal_0.9_react_13.gemfile +4 -0
  15. data/gemfiles/opal_0.9_react_14.gemfile +4 -0
  16. data/gemfiles/opal_0.9_react_15.gemfile +4 -0
  17. data/gemfiles/opal_master_react_15.gemfile +18 -0
  18. data/hyper-react.gemspec +4 -0
  19. data/lib/hyper-react.rb +24 -4
  20. data/lib/rails-helpers/top_level_rails_component.rb +1 -1
  21. data/lib/react/api.rb +10 -0
  22. data/lib/react/component.rb +135 -106
  23. data/lib/react/component/base.rb +5 -1
  24. data/lib/react/component/class_methods.rb +12 -37
  25. data/lib/react/component/dsl_instance_methods.rb +0 -4
  26. data/lib/react/component/props_wrapper.rb +0 -5
  27. data/lib/react/component/should_component_update.rb +1 -5
  28. data/lib/react/component/tags.rb +7 -22
  29. data/lib/react/config.rb +5 -0
  30. data/lib/react/config/client.rb.erb +19 -0
  31. data/lib/react/config/server.rb +20 -0
  32. data/lib/react/element.rb +1 -0
  33. data/lib/react/native_library.rb +2 -7
  34. data/lib/react/react-source-browser.rb +3 -0
  35. data/lib/react/react-source-server.rb +3 -0
  36. data/lib/react/react-source.rb +12 -1
  37. data/lib/react/ref_callback.rb +31 -0
  38. data/lib/react/rendering_context.rb +9 -9
  39. data/lib/react/server.rb +23 -0
  40. data/lib/react/state_wrapper.rb +23 -0
  41. data/lib/react/test/matchers/render_html_matcher.rb +4 -2
  42. data/lib/react/top_level.rb +2 -0
  43. data/lib/reactive-ruby/component_loader.rb +2 -1
  44. data/lib/reactive-ruby/isomorphic_helpers.rb +10 -0
  45. data/lib/reactive-ruby/version.rb +1 -1
  46. data/lib/reactrb/auto-import.rb +2 -7
  47. data/spec/react/callbacks_spec.rb +8 -7
  48. data/spec/react/component_spec.rb +24 -13
  49. data/spec/react/dsl_spec.rb +12 -8
  50. data/spec/react/element_spec.rb +7 -7
  51. data/spec/react/native_library_spec.rb +25 -43
  52. data/spec/react/param_declaration_spec.rb +9 -0
  53. data/spec/react/react_spec.rb +0 -7
  54. data/spec/react/refs_callback_spec.rb +56 -0
  55. data/spec/react/server_spec.rb +25 -0
  56. data/spec/react/state_spec.rb +3 -3
  57. data/spec/react/top_level_component_spec.rb +1 -1
  58. data/spec/spec_helper.rb +31 -1
  59. metadata +72 -9
  60. data/lib/react/observable.rb +0 -29
  61. data/lib/react/state.rb +0 -191
  62. data/lib/sources/react-latest.js +0 -21169
  63. data/lib/sources/react-v13.js +0 -21645
  64. data/lib/sources/react-v14.js +0 -20821
  65. data/lib/sources/react-v15.js +0 -21170
@@ -84,6 +84,7 @@ module React
84
84
  end
85
85
 
86
86
  def self.render_to_string(element)
87
+ %x{ console.error("Warning: `React.render_to_string` is deprecated in favor of `React::Server.render_to_string`."); }
87
88
  if !(`typeof ReactDOMServer === 'undefined'`)
88
89
  React::RenderingContext.build { `ReactDOMServer.renderToString(#{element.to_n})` } # v0.15+
89
90
  elsif !(`typeof React.renderToString === 'undefined'`)
@@ -94,6 +95,7 @@ module React
94
95
  end
95
96
 
96
97
  def self.render_to_static_markup(element)
98
+ %x{ console.error("Warning: `React.render_to_static_markup` is deprecated in favor of `React::Server.render_to_static_markup`."); }
97
99
  if !(`typeof ReactDOMServer === 'undefined'`)
98
100
  React::RenderingContext.build { `ReactDOMServer.renderToStaticMarkup(#{element.to_n})` } # v0.15+
99
101
  elsif !(`typeof React.renderToString === 'undefined'`)
@@ -29,7 +29,8 @@ module ReactiveRuby
29
29
  private
30
30
 
31
31
  def components
32
- # Make this configurable at some point
32
+ opts = ::Rails.configuration.react.server_renderer_options
33
+ return opts[:files].first.gsub(/.js$/,'') if opts && opts[:files]
33
34
  'components'
34
35
  end
35
36
 
@@ -1,3 +1,5 @@
1
+ require "react/config"
2
+
1
3
  module React
2
4
  module IsomorphicHelpers
3
5
  def self.included(base)
@@ -28,6 +30,13 @@ module React
28
30
 
29
31
  def self.log(message, message_type = :info)
30
32
  message = [message] unless message.is_a? Array
33
+
34
+ is_production = React::Config.config[:environment] == 'production'
35
+
36
+ if (message_type == :info || message_type == :warning) && is_production
37
+ return
38
+ end
39
+
31
40
  if message_type == :info
32
41
  if on_opal_server?
33
42
  style = 'background: #00FFFF; color: red'
@@ -102,6 +111,7 @@ module React
102
111
  ctx["ServerSideIsomorphicMethods"] = self
103
112
  send_to_opal(:load_context, @unique_id, name)
104
113
  end
114
+ Hyperloop::Application::Boot.run(context: self)
105
115
  self.class.before_first_mount_blocks.each { |block| block.call(self) }
106
116
  end
107
117
 
@@ -1,3 +1,3 @@
1
1
  module React
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
@@ -17,15 +17,10 @@ if RUBY_ENGINE == 'opal'
17
17
  React::NativeLibrary.import_const_from_native(Object, const_name, true) || raise(e)
18
18
  end
19
19
 
20
- def method_missing(method_name, *args, &block)
21
- method = method_name.gsub(/_as_node/, '') # remove once _as_node is deprecated.
20
+ def method_missing(method, *args, &block)
22
21
  component_class = React::NativeLibrary.import_const_from_native(self, method, false)
23
22
  _reactrb_original_method_missing(method, *args, &block) unless component_class
24
- if method == method_name
25
- React::RenderingContext.render(component_class, *args, &block)
26
- else # remove once _as_node is deprecated.
27
- React::RenderingContext.build_only(component_class, *args, &block)
28
- end
23
+ React::RenderingContext.render(component_class, *args, &block)
29
24
  end
30
25
  end
31
26
  end
@@ -13,8 +13,9 @@ describe React::Callbacks do
13
13
  end
14
14
  end
15
15
 
16
- expect_any_instance_of(Foo).to receive(:wash_hand)
17
- Foo.new.run_callback(:before_dinner)
16
+ instance = Foo.new
17
+ expect(instance).to receive(:wash_hand)
18
+ instance.run_callback(:before_dinner)
18
19
  end
19
20
 
20
21
  it 'defines multiple callbacks' do
@@ -30,9 +31,10 @@ describe React::Callbacks do
30
31
  def turn_of_laptop;end
31
32
  end
32
33
 
33
- expect_any_instance_of(Foo).to receive(:wash_hand)
34
- expect_any_instance_of(Foo).to receive(:turn_of_laptop)
35
- Foo.new.run_callback(:before_dinner)
34
+ instance = Foo.new
35
+ expect(instance).to receive(:wash_hand)
36
+ expect(instance).to receive(:turn_of_laptop)
37
+ instance.run_callback(:before_dinner)
36
38
  end
37
39
 
38
40
  it 'defines block callback' do
@@ -95,9 +97,8 @@ describe React::Callbacks do
95
97
  def eat_ice_cream(a,b,c); end
96
98
  end
97
99
 
98
- expect_any_instance_of(Foo).to receive(:eat_ice_cream).with(4,5,6)
99
-
100
100
  foo = Foo.new
101
+ expect(foo).to receive(:eat_ice_cream).with(4,5,6)
101
102
  foo.run_callback(:before_dinner, 1, 2)
102
103
  foo.run_callback(:after_dinner, 4, 5, 6)
103
104
  expect(foo.lorem).to eq('1-2')
@@ -186,7 +186,7 @@ describe React::Component, type: :component do
186
186
  define_state :foo
187
187
  before_mount :set_up
188
188
  def set_up
189
- self.foo = 'bar'
189
+ mutate.foo 'bar'
190
190
  end
191
191
  end
192
192
 
@@ -208,7 +208,7 @@ describe React::Component, type: :component do
208
208
  define_state(:foo) { 10 }
209
209
  before_mount :bump
210
210
  def bump
211
- self.foo = self.foo + 20
211
+ mutate.foo(state.foo + 20)
212
212
  end
213
213
  end
214
214
 
@@ -221,8 +221,8 @@ describe React::Component, type: :component do
221
221
  define_state :foo, :foo2
222
222
  before_mount :set_up
223
223
  def set_up
224
- self.foo = 10
225
- self.foo2 = 20
224
+ mutate.foo 10
225
+ mutate.foo2 20
226
226
  end
227
227
  end
228
228
 
@@ -267,7 +267,7 @@ describe React::Component, type: :component do
267
267
  Foo.class_eval do
268
268
  define_state(:foo) { 10 }
269
269
  def render
270
- React.create_element('div') { self.foo }
270
+ React.create_element('div') { state.foo }
271
271
  end
272
272
  end
273
273
 
@@ -289,12 +289,16 @@ describe React::Component, type: :component do
289
289
  it 'supports original `replaceState` as `set_state!` method' do
290
290
  Foo.class_eval do
291
291
  before_mount do
292
- self.set_state(foo: 'bar')
293
- self.set_state!(bar: 'lorem')
292
+ set_state(foo: 'bar')
293
+ set_state!(bar: 'lorem')
294
294
  end
295
295
  end
296
296
 
297
297
  element = renderToDocument(Foo)
298
+ puts "*************************************************************************************"
299
+ puts "element.state[:foo] = #{element.state[:foo]}"
300
+ puts "element.state[:bar] = #{element.state[:bar]}"
301
+ puts "*************************************************************************************"
298
302
  expect(element.state[:foo]).to be_nil
299
303
  expect(element.state[:bar]).to eq('lorem')
300
304
  end
@@ -318,11 +322,11 @@ describe React::Component, type: :component do
318
322
  define_state :foo
319
323
 
320
324
  before_mount do
321
- self.foo = [{a: "Hello"}]
325
+ mutate.foo [{a: "Hello"}]
322
326
  end
323
327
 
324
328
  def render
325
- div { self.foo[0][:a] }
329
+ div { state.foo[0][:a] }
326
330
  end
327
331
  end
328
332
 
@@ -567,7 +571,7 @@ describe React::Component, type: :component do
567
571
 
568
572
  def render
569
573
  React.create_element('div').on(:click) do
570
- self.clicked = true
574
+ mutate.clicked true
571
575
  end
572
576
  end
573
577
  end
@@ -580,10 +584,15 @@ describe React::Component, type: :component do
580
584
 
581
585
  it 'invokes handler on `this.props` using emit' do
582
586
  Foo.class_eval do
587
+ param :_onFooSubmit, type: Proc
583
588
  after_mount :setup
584
589
 
585
590
  def setup
591
+ puts "***************************** about to emit******************************"
586
592
  self.emit(:foo_submit, 'bar')
593
+ puts "***************************** emitted!!! ********************************"
594
+ rescue Exception => e
595
+ puts "FAILED FAILED FAILED #{e}"
587
596
  end
588
597
 
589
598
  def render
@@ -599,6 +608,7 @@ describe React::Component, type: :component do
599
608
 
600
609
  it 'invokes handler with multiple params using emit' do
601
610
  Foo.class_eval do
611
+ param :_onFooInvoked, type: Proc
602
612
  after_mount :setup
603
613
 
604
614
  def setup
@@ -712,15 +722,16 @@ describe React::Component, type: :component do
712
722
  include React::Component
713
723
 
714
724
  def render
715
- p(class_name: 'foo') do
725
+ div {
726
+ p(class_name: 'foo')
716
727
  p
717
728
  div { 'lorem ipsum' }
718
729
  p(id: '10')
719
- end
730
+ }
720
731
  end
721
732
  end
722
733
 
723
- markup = '<p class="foo"><p></p><div>lorem ipsum</div><p id="10"></p></p>'
734
+ markup = '<div><p class="foo"></p><p></p><div>lorem ipsum</div><p id="10"></p></div>'
724
735
  expect(Foo).to render_static_html(markup)
725
736
  end
726
737
 
@@ -65,7 +65,7 @@ describe 'the React DSL', type: :component do
65
65
  end
66
66
  end
67
67
 
68
- expect(React.render_to_static_markup(React.create_element(Foo))).to match(/<input data-foo="12"(\/)?>/)
68
+ expect(React::Server.render_to_static_markup(React.create_element(Foo))).to match(/<input data-foo="12"(\/)?>/)
69
69
  end
70
70
 
71
71
  it "will turn the last string in a block into a element" do
@@ -101,7 +101,7 @@ describe 'the React DSL', type: :component do
101
101
  end
102
102
  end
103
103
 
104
- expect(React.render_to_static_markup(React.create_element(Foo)).gsub("<br/>", "<br>")).to eq('<div><span>hello<br></span></div>')
104
+ expect(React::Server.render_to_static_markup(React.create_element(Foo)).gsub("<br/>", "<br>")).to eq('<div><span>hello<br></span></div>')
105
105
  end
106
106
 
107
107
  it "has a .td short hand String method" do
@@ -109,11 +109,15 @@ describe 'the React DSL', type: :component do
109
109
  Foo.class_eval do
110
110
  include React::Component
111
111
  def render
112
- table { tr { "hello".td } }
112
+ table {
113
+ tbody {
114
+ tr { "hello".td }
115
+ }
116
+ }
113
117
  end
114
118
  end
115
119
 
116
- expect(Foo).to render_static_html('<table><tr><td>hello</td></tr></table>')
120
+ expect(Foo).to render_static_html('<table><tbody><tr><td>hello</td></tr></tbody></table>')
117
121
  end
118
122
 
119
123
  it "has a .para short hand String method" do
@@ -156,7 +160,7 @@ describe 'the React DSL', type: :component do
156
160
  Comp()
157
161
  end
158
162
  end
159
- expect { React.render_to_static_markup(React.create_element(Mod::NestedMod::NestedComp)) }
163
+ expect { React::Server.render_to_static_markup(React.create_element(Mod::NestedMod::NestedComp)) }
160
164
  .to raise_error('Comp does not appear to be a react component.')
161
165
  end
162
166
 
@@ -168,7 +172,7 @@ describe 'the React DSL', type: :component do
168
172
  _undefined_method
169
173
  end
170
174
  end
171
- expect { React.render_to_static_markup(React.create_element(Foo)) }
175
+ expect { React::Server.render_to_static_markup(React.create_element(Foo)) }
172
176
  .to raise_error(NoMethodError)
173
177
  end
174
178
 
@@ -251,12 +255,12 @@ describe 'the React DSL', type: :component do
251
255
  Foo.class_eval do
252
256
  include React::Component
253
257
  def render
254
- div(data: { foo: :bar }, aria: { foo_bar: :foo })
258
+ div(data: { foo: :bar }, aria: { label: "title" })
255
259
  end
256
260
  end
257
261
 
258
262
  expect(Foo)
259
- .to render_static_html('<div data-foo="bar" aria-foo-bar="foo"></div>')
263
+ .to render_static_html('<div data-foo="bar" aria-label="title"></div>')
260
264
  end
261
265
 
262
266
  it 'should not convert a hash param to hyphenated html attributes if not in React::HASH_ATTRIBUTES' do
@@ -29,7 +29,7 @@ describe React::Element, type: :component do
29
29
  end
30
30
  end
31
31
 
32
- expect(React.render_to_static_markup(React.create_element(Foo))).to match(/<input (type="text" value=""|value="" type="text")(\/)?>/)
32
+ expect(React::Server.render_to_static_markup(React.create_element(Foo))).to match(/<input (type="text" value=""|value="" type="text")(\/)?>/)
33
33
  end
34
34
  end
35
35
 
@@ -43,7 +43,7 @@ describe React::Element, type: :component do
43
43
  params.on_event
44
44
  end
45
45
  end
46
- expect(React.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
46
+ expect(React::Server.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
47
47
  end
48
48
 
49
49
  it 'will subscribe to multiple component event params' do
@@ -55,7 +55,7 @@ describe React::Element, type: :component do
55
55
  params.on_event1+params.on_event2
56
56
  end
57
57
  end
58
- expect(React.render_to_static_markup(React.create_element(Foo).on(:event1, :event2) {'works!'})).to eq('<span>works!works!</span>')
58
+ expect(React::Server.render_to_static_markup(React.create_element(Foo).on(:event1, :event2) {'works!'})).to eq('<span>works!works!</span>')
59
59
  end
60
60
 
61
61
  it 'will subscribe to a native components event param' do
@@ -71,7 +71,7 @@ describe React::Element, type: :component do
71
71
  Foo.class_eval do
72
72
  imports "NativeComponent"
73
73
  end
74
- expect(React.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
74
+ expect(React::Server.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
75
75
  end
76
76
 
77
77
  it 'will subscribe to a component event param with a non-default name' do
@@ -82,7 +82,7 @@ describe React::Element, type: :component do
82
82
  params.my_event
83
83
  end
84
84
  end
85
- expect(React.render_to_static_markup(React.create_element(Foo).on("<my_event>") {'works!'})).to eq('<span>works!</span>')
85
+ expect(React::Server.render_to_static_markup(React.create_element(Foo).on("<my_event>") {'works!'})).to eq('<span>works!</span>')
86
86
  end
87
87
 
88
88
  it 'will subscribe to a component event param using the deprecated naming convention and generate a message' do
@@ -99,10 +99,10 @@ describe React::Element, type: :component do
99
99
  var org_error_console = window.console.error;
100
100
  window.console.warn = window.console.error = function(str){log.push(str)}
101
101
  }
102
- expect(React.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
102
+ expect(React::Server.render_to_static_markup(React.create_element(Foo).on(:event) {'works!'})).to eq('<span>works!</span>')
103
103
  `window.console.warn = org_warn_console; window.console.error = org_error_console;`
104
104
  expect(`log[0]`).to match(/Warning: Failed prop( type|Type): In component `Foo`\nProvided prop `on_event` not specified in spec/)
105
- expect(`log[1]`).to eq("Warning: Deprecated feature used in React::Component. In future releases React::Element#on('event') will no longer respond to the '_onEvent' emitter.\nRename your emitter param to 'on_event' or use .on('<_onEvent>')")
105
+ expect(`log[1]`).to eq("Warning: Deprecated feature used in Foo. In future releases React::Element#on('event') will no longer respond to the '_onEvent' emitter.\nRename your emitter param to 'on_event' or use .on('<_onEvent>')")
106
106
  end
107
107
  end
108
108
 
@@ -205,6 +205,28 @@ describe "React::NativeLibrary", type: :component do
205
205
  end.to raise_error(/^Foo cannot import \'window\.Baz\'\: (?!does not appear to be a native react component)..*$/)
206
206
  end
207
207
 
208
+ it "allows passing native object as props" do
209
+ %x{
210
+ window.NativeComponent = React.createClass({
211
+ displayName: "HelloMessage",
212
+ render: function render() {
213
+ return React.createElement("div", null, "Hello ", this.props.user.name);
214
+ }
215
+ })
216
+ }
217
+ stub_const 'Foo', Class.new(React::Component::Base)
218
+ Foo.class_eval do
219
+ imports "NativeComponent"
220
+ end
221
+ stub_const 'Wrapper', Class.new(React::Component::Base)
222
+ Wrapper.class_eval do
223
+ def render
224
+ Foo(user: `{name: 'David'}`)
225
+ end
226
+ end
227
+ expect(Wrapper).to render_static_html('<div>Hello David</div>')
228
+ end
229
+
208
230
  context "automatic importing" do
209
231
 
210
232
  it "will automatically import a React.js component when referenced in another component" do
@@ -216,7 +238,7 @@ describe "React::NativeLibrary", type: :component do
216
238
  }
217
239
  })
218
240
  }
219
- expect(React.render_to_static_markup(
241
+ expect(React::Server.render_to_static_markup(
220
242
  React.create_element(NativeLibraryTestModule::Component, time_stamp: Time.now))).to match(/<div>Hello There.*<\/div>/)
221
243
  end
222
244
 
@@ -236,46 +258,6 @@ describe "React::NativeLibrary", type: :component do
236
258
  expect(Foo).to render_static_html('<div>Hello There</div>')
237
259
  end
238
260
 
239
- it 'will automatically import a React.js component when referenced in another component with the _as_node suffix' do
240
- stub_const 'Foo', Class.new(React::Component::Base)
241
- Foo.class_eval do
242
- render(:div) do
243
- e = React::Element.new(NativeComponent_as_node(name: 'There'))
244
- 2.times { e.render }
245
- end
246
- end
247
- %x{
248
- window.NativeComponent = React.createClass({
249
- displayName: "HelloMessage",
250
- render: function render() {
251
- return React.createElement("div", null, "Hello ", this.props.name);
252
- }
253
- })
254
- }
255
- expect(Foo).to render_static_html('<div><div>Hello There</div><div>Hello There</div></div>')
256
- end
257
-
258
- it "will automatically import a React.js component in a library when referenced in another component with the _as_node suffix" do
259
- stub_const 'Foo', Class.new(React::Component::Base)
260
- Foo.class_eval do
261
- render(:div) do
262
- e = React::Element.new(NativeLibrary::NativeComponent_as_node(name: 'There'))
263
- 2.times { e.render }
264
- end
265
- end
266
- %x{
267
- window.NativeLibrary = {
268
- NativeComponent: React.createClass({
269
- displayName: "HelloMessage",
270
- render: function render() {
271
- return React.createElement("div", null, "Hello ", this.props.name);
272
- }
273
- })
274
- }
275
- }
276
- expect(Foo).to render_static_html('<div><div>Hello There</div><div>Hello There</div></div>')
277
- end
278
-
279
261
  it "will automatically import a React.js component when referenced as a constant" do
280
262
  %x{
281
263
  window.NativeComponent = React.createClass({
@@ -303,7 +285,7 @@ describe "React::NativeLibrary", type: :component do
303
285
  }
304
286
  }
305
287
 
306
- expect(React.render_to_static_markup(
288
+ expect(React::Server.render_to_static_markup(
307
289
  React.create_element(NativeLibraryTestModule::NestedComponent, time_stamp: Time.now))).to match(/<div>Hello There.*<\/div>/)
308
290
  end
309
291
 
@@ -330,7 +312,7 @@ describe "React::NativeLibrary", type: :component do
330
312
  }
331
313
  }
332
314
  expect do
333
- React.render_to_static_markup(React.create_element(NativeLibraryTestModule::NestedComponent, time_stamp: Time.now))
315
+ React::Server.render_to_static_markup(React.create_element(NativeLibraryTestModule::NestedComponent, time_stamp: Time.now))
334
316
  end.to raise_error("could not import a react component named: NativeLibrary.NativeNestedLibrary.NativeComponent")
335
317
 
336
318
  end