hyper-react 0.99.6 → 1.0.0.lap21

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 (187) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +27 -0
  3. data/.gitignore +30 -37
  4. data/.rubocop.yml +1159 -0
  5. data/.travis.yml +32 -0
  6. data/Appraisals +31 -0
  7. data/CHANGELOG.md +143 -0
  8. data/DOCS.md +1515 -0
  9. data/Gemfile +2 -5
  10. data/LICENSE +19 -0
  11. data/README.md +5 -33
  12. data/Rakefile +25 -6
  13. data/UPGRADING.md +24 -0
  14. data/component-name-lookup.md +145 -0
  15. data/dciy.toml +3 -0
  16. data/dciy_prepare.sh +8 -0
  17. data/dciy_run.sh +10 -0
  18. data/hyper-react.gemspec +24 -18
  19. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
  20. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +5 -0
  21. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
  22. data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
  23. data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
  24. data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
  25. data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
  26. data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
  27. data/lib/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
  28. data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +117 -0
  29. data/lib/hyper-react.rb +66 -4
  30. data/lib/rails-helpers/top_level_rails_component.rb +75 -0
  31. data/lib/react/api.rb +203 -0
  32. data/lib/react/callbacks.rb +41 -0
  33. data/lib/react/children.rb +30 -0
  34. data/lib/react/component.rb +177 -0
  35. data/lib/react/component/api.rb +69 -0
  36. data/lib/react/component/base.rb +13 -0
  37. data/lib/react/component/class_methods.rb +181 -0
  38. data/lib/react/component/dsl_instance_methods.rb +23 -0
  39. data/lib/react/component/params.rb +6 -0
  40. data/lib/react/component/props_wrapper.rb +78 -0
  41. data/lib/react/component/should_component_update.rb +99 -0
  42. data/lib/react/component/tags.rb +108 -0
  43. data/lib/react/config.rb +5 -0
  44. data/lib/react/config/client.rb.erb +19 -0
  45. data/lib/react/config/server.rb +23 -0
  46. data/lib/react/element.rb +150 -0
  47. data/lib/react/event.rb +76 -0
  48. data/lib/react/ext/hash.rb +9 -0
  49. data/lib/react/ext/opal-jquery/element.rb +26 -0
  50. data/lib/react/ext/string.rb +8 -0
  51. data/lib/react/hash.rb +13 -0
  52. data/lib/react/native_library.rb +87 -0
  53. data/lib/react/object.rb +15 -0
  54. data/lib/react/react-source-browser.rb +3 -0
  55. data/lib/react/react-source-server.rb +3 -0
  56. data/lib/react/react-source.rb +16 -0
  57. data/lib/react/ref_callback.rb +31 -0
  58. data/lib/react/rendering_context.rb +146 -0
  59. data/lib/react/server.rb +19 -0
  60. data/lib/react/state_wrapper.rb +23 -0
  61. data/lib/react/test.rb +16 -0
  62. data/lib/react/test/dsl.rb +17 -0
  63. data/lib/react/test/matchers/render_html_matcher.rb +56 -0
  64. data/lib/react/test/rspec.rb +15 -0
  65. data/lib/react/test/session.rb +37 -0
  66. data/lib/react/test/utils.rb +71 -0
  67. data/lib/react/top_level.rb +110 -0
  68. data/lib/react/top_level_render.rb +28 -0
  69. data/lib/react/validator.rb +136 -0
  70. data/lib/reactive-ruby/component_loader.rb +43 -0
  71. data/lib/reactive-ruby/isomorphic_helpers.rb +235 -0
  72. data/lib/reactive-ruby/rails.rb +8 -0
  73. data/lib/reactive-ruby/rails/component_mount.rb +48 -0
  74. data/lib/reactive-ruby/rails/controller_helper.rb +14 -0
  75. data/lib/reactive-ruby/rails/railtie.rb +20 -0
  76. data/lib/reactive-ruby/serializers.rb +15 -0
  77. data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +41 -0
  78. data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +46 -0
  79. data/lib/reactive-ruby/version.rb +3 -0
  80. data/lib/reactrb/auto-import.rb +27 -0
  81. data/logo1.png +0 -0
  82. data/logo2.png +0 -0
  83. data/logo3.png +0 -0
  84. data/path_release_steps.md +9 -0
  85. data/spec/controller_helper_spec.rb +35 -0
  86. data/spec/index.html.erb +11 -0
  87. data/spec/react/callbacks_spec.rb +142 -0
  88. data/spec/react/children_spec.rb +132 -0
  89. data/spec/react/component/base_spec.rb +36 -0
  90. data/spec/react/component_spec.rb +1073 -0
  91. data/spec/react/dsl_spec.rb +323 -0
  92. data/spec/react/element_spec.rb +132 -0
  93. data/spec/react/event_spec.rb +39 -0
  94. data/spec/react/native_library_spec.rb +387 -0
  95. data/spec/react/observable_spec.rb +31 -0
  96. data/spec/react/opal_jquery_extensions_spec.rb +68 -0
  97. data/spec/react/param_declaration_spec.rb +253 -0
  98. data/spec/react/react_spec.rb +278 -0
  99. data/spec/react/refs_callback_spec.rb +65 -0
  100. data/spec/react/server_spec.rb +25 -0
  101. data/spec/react/state_spec.rb +52 -0
  102. data/spec/react/test/dsl_spec.rb +43 -0
  103. data/spec/react/test/matchers/render_html_matcher_spec.rb +83 -0
  104. data/spec/react/test/rspec_spec.rb +62 -0
  105. data/spec/react/test/session_spec.rb +88 -0
  106. data/spec/react/test/utils_spec.rb +28 -0
  107. data/spec/react/top_level_component_spec.rb +103 -0
  108. data/spec/react/tutorial/tutorial_spec.rb +42 -0
  109. data/spec/react/validator_spec.rb +134 -0
  110. data/spec/reactive-ruby/component_loader_spec.rb +74 -0
  111. data/spec/reactive-ruby/isomorphic_helpers_spec.rb +157 -0
  112. data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +17 -0
  113. data/spec/reactive-ruby/rails/component_mount_spec.rb +64 -0
  114. data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +39 -0
  115. data/spec/spec_helper.rb +55 -0
  116. data/spec/test_app/README.md +24 -0
  117. data/spec/test_app/Rakefile +6 -0
  118. data/spec/test_app/app/assets/config/manifest.js +3 -0
  119. data/spec/test_app/app/assets/images/.keep +0 -0
  120. data/spec/test_app/app/assets/javascripts/application.rb +7 -0
  121. data/spec/test_app/app/assets/javascripts/cable.js +13 -0
  122. data/spec/test_app/app/assets/javascripts/channels/.keep +0 -0
  123. data/spec/test_app/app/assets/javascripts/server_rendering.js +5 -0
  124. data/spec/test_app/app/assets/stylesheets/application.css +15 -0
  125. data/spec/test_app/app/channels/application_cable/channel.rb +4 -0
  126. data/spec/test_app/app/channels/application_cable/connection.rb +4 -0
  127. data/spec/test_app/app/controllers/application_controller.rb +3 -0
  128. data/spec/test_app/app/controllers/concerns/.keep +0 -0
  129. data/spec/test_app/app/helpers/application_helper.rb +2 -0
  130. data/spec/test_app/app/jobs/application_job.rb +2 -0
  131. data/spec/test_app/app/mailers/application_mailer.rb +4 -0
  132. data/spec/test_app/app/models/application_record.rb +3 -0
  133. data/spec/test_app/app/models/concerns/.keep +0 -0
  134. data/spec/test_app/app/views/components.rb +11 -0
  135. data/spec/test_app/app/views/components/hello_world.rb +11 -0
  136. data/spec/test_app/app/views/components/todo.rb +14 -0
  137. data/spec/test_app/app/views/layouts/application.html.erb +14 -0
  138. data/spec/test_app/app/views/layouts/explicit_layout.html.erb +0 -0
  139. data/spec/test_app/app/views/layouts/mailer.html.erb +13 -0
  140. data/spec/test_app/app/views/layouts/mailer.text.erb +1 -0
  141. data/spec/test_app/app/views/layouts/test_layout.html.erb +0 -0
  142. data/spec/test_app/bin/bundle +3 -0
  143. data/spec/test_app/bin/rails +4 -0
  144. data/spec/test_app/bin/rake +4 -0
  145. data/spec/test_app/bin/setup +38 -0
  146. data/spec/test_app/bin/update +29 -0
  147. data/spec/test_app/bin/yarn +11 -0
  148. data/spec/test_app/config.ru +5 -0
  149. data/spec/test_app/config/application.rb +45 -0
  150. data/spec/test_app/config/boot.rb +6 -0
  151. data/spec/test_app/config/cable.yml +10 -0
  152. data/spec/test_app/config/database.yml +25 -0
  153. data/spec/test_app/config/environment.rb +5 -0
  154. data/spec/test_app/config/environments/development.rb +54 -0
  155. data/spec/test_app/config/environments/production.rb +91 -0
  156. data/spec/test_app/config/environments/test.rb +42 -0
  157. data/spec/test_app/config/initializers/application_controller_renderer.rb +8 -0
  158. data/spec/test_app/config/initializers/assets.rb +14 -0
  159. data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
  160. data/spec/test_app/config/initializers/cookies_serializer.rb +5 -0
  161. data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
  162. data/spec/test_app/config/initializers/inflections.rb +16 -0
  163. data/spec/test_app/config/initializers/mime_types.rb +4 -0
  164. data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
  165. data/spec/test_app/config/locales/en.yml +33 -0
  166. data/spec/test_app/config/puma.rb +56 -0
  167. data/spec/test_app/config/routes.rb +3 -0
  168. data/spec/test_app/config/secrets.yml +32 -0
  169. data/spec/test_app/config/spring.rb +6 -0
  170. data/spec/test_app/db/development.sqlite3 +0 -0
  171. data/spec/test_app/db/schema.rb +15 -0
  172. data/spec/test_app/db/seeds.rb +7 -0
  173. data/spec/test_app/db/test.sqlite3 +0 -0
  174. data/spec/test_app/lib/assets/.keep +0 -0
  175. data/spec/test_app/log/.keep +0 -0
  176. data/spec/test_app/package.json +5 -0
  177. data/spec/test_app/public/404.html +67 -0
  178. data/spec/test_app/public/422.html +67 -0
  179. data/spec/test_app/public/500.html +66 -0
  180. data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
  181. data/spec/test_app/public/apple-touch-icon.png +0 -0
  182. data/spec/test_app/public/favicon.ico +0 -0
  183. data/spec/vendor/es5-shim.min.js +7 -0
  184. data/spec/vendor/jquery-2.2.4.min.js +4 -0
  185. metadata +401 -61
  186. data/CODE_OF_CONDUCT.md +0 -49
  187. data/lib/react/version.rb +0 -3
@@ -0,0 +1,14 @@
1
+ module Components
2
+ class Todo
3
+ include React::Component
4
+ export_component
5
+
6
+ params do
7
+ requires :todo
8
+ end
9
+
10
+ def render
11
+ li { "#{params[:todo]}" }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,117 @@
1
+ require 'rails/generators/rails/app/app_generator'
2
+
3
+ module ReactiveRuby
4
+ class TestAppGenerator < ::Rails::Generators::Base
5
+ def self.source_paths
6
+ paths = self.superclass.source_paths
7
+ paths << File.expand_path('../templates', __FILE__)
8
+ paths.flatten
9
+ end
10
+
11
+ def remove_existing_app
12
+ remove_dir(test_app_path) if File.directory?(test_app_path)
13
+ end
14
+
15
+ def generate_test_app
16
+ opts = options.dup
17
+ opts[:database] = 'sqlite3' if opts[:database].blank?
18
+ opts[:force] = true
19
+ opts[:skip_bundle] = true
20
+
21
+ puts "Generating Test Rails Application..."
22
+ invoke ::Rails::Generators::AppGenerator,
23
+ [ File.expand_path(test_app_path, destination_root) ], opts
24
+ end
25
+
26
+ def configure_test_app
27
+ template 'boot.rb.erb', "#{test_app_path}/config/boot.rb", force: true
28
+ template 'test_application.rb.erb', "#{test_app_path}/config/application.rb", force: true
29
+ template 'assets/javascripts/test_application.rb',
30
+ "#{test_app_path}/app/assets/javascripts/application.rb", force: true
31
+ template 'assets/javascripts/server_rendering.js',
32
+ "#{test_app_path}/app/assets/javascripts/server_rendering.js", force: true
33
+ template 'assets/javascripts/components.rb',
34
+ "#{test_app_path}/app/views/components.rb", force: true
35
+ template 'views/components/hello_world.rb',
36
+ "#{test_app_path}/app/views/components/hello_world.rb", force: true
37
+ template 'views/components/todo.rb',
38
+ "#{test_app_path}/app/views/components/todo.rb", force: true
39
+ template 'views/layouts/test_layout.html.erb',
40
+ "#{test_app_path}/app/views/layouts/test_layout.html.erb", force: true
41
+ template 'views/layouts/test_layout.html.erb',
42
+ "#{test_app_path}/app/views/layouts/explicit_layout.html.erb", force: true
43
+ end
44
+
45
+ def clean_superfluous_files
46
+ inside test_app_path do
47
+ remove_file '.gitignore'
48
+ remove_file 'doc'
49
+ remove_file 'Gemfile'
50
+ remove_file 'lib/tasks'
51
+ remove_file 'app/assets/images/rails.png'
52
+ remove_file 'app/assets/javascripts/application.js'
53
+ remove_file 'public/index.html'
54
+ remove_file 'public/robots.txt'
55
+ remove_file 'README.rdoc'
56
+ remove_file 'test'
57
+ remove_file 'vendor'
58
+ remove_file 'spec'
59
+ end
60
+ end
61
+
62
+ def configure_opal_rspec
63
+ inject_into_file "#{test_app_path}/config/application.rb",
64
+ after: /class Application < Rails::Application/, verbose: true do
65
+ %Q[
66
+ config.opal.method_missing = true
67
+ config.opal.optimized_operators = true
68
+ config.opal.arity_check = false
69
+ config.opal.const_missing = true
70
+ config.opal.dynamic_require_severity = :ignore
71
+ config.opal.enable_specs = true
72
+ config.opal.spec_location = 'spec-opal'
73
+ config.hyperloop.auto_config = false
74
+
75
+ config.react.server_renderer_options = {
76
+ files: ["server_rendering.js"]
77
+ }
78
+ config.react.server_renderer_directories = ["/app/assets/javascripts"]
79
+ ]
80
+ end
81
+ end
82
+
83
+ protected
84
+
85
+ def application_definition
86
+ @application_definition ||= begin
87
+ test_application_contents
88
+ end
89
+ end
90
+ alias :store_application_definition! :application_definition
91
+
92
+ private
93
+
94
+ def test_app_path
95
+ 'spec/test_app'
96
+ end
97
+
98
+ def test_application_path
99
+ File.expand_path("#{test_app_path}/config/application.rb",
100
+ destination_root)
101
+ end
102
+
103
+ def test_application_contents
104
+ return unless File.exists?(test_application_path) && !options[:pretend]
105
+ contents = File.read(test_application_path)
106
+ contents[(contents.index("module #{module_name}"))..-1]
107
+ end
108
+
109
+ def module_name
110
+ 'TestApp'
111
+ end
112
+
113
+ def gemfile_path
114
+ '../../../../Gemfile'
115
+ end
116
+ end
117
+ end
@@ -1,8 +1,70 @@
1
- require 'hyper-component'
2
- require 'react/version'
1
+ require 'hyperloop-config'
2
+ Hyperloop.import 'hyper-store'
3
+ Hyperloop.import 'react/react-source-browser', client_only: true
4
+ Hyperloop.import 'react/react-source-server', server_only: true
5
+ Hyperloop.import 'browser/delay', client_only: true
3
6
  Hyperloop.import 'hyper-react'
7
+ Hyperloop.import 'react_ujs'
4
8
 
5
- if RUBY_ENGINE != 'opal'
9
+ if RUBY_ENGINE == 'opal'
10
+ module Hyperloop
11
+ class Component
12
+ end
13
+ end
14
+
15
+ if `Opal.global.React === undefined || Opal.global.React.version === undefined`
16
+ raise [
17
+ "No React.js Available",
18
+ "",
19
+ "A global `React` must be defined before requiring 'hyper-react'",
20
+ "",
21
+ "To USE THE BUILT-IN SOURCE: ",
22
+ " add 'require \"react/react-source-browser\"' immediately before the 'require \"hyper-react\" directive.",
23
+ "IF USING WEBPACK:",
24
+ " add 'react' to your webpack manifest."
25
+ ].join("\n")
26
+ end
27
+ require 'react/hash'
28
+ require 'react/top_level'
29
+ require 'react/top_level_render'
30
+ require 'react/observable'
31
+ require 'react/validator'
32
+ require 'react/component'
33
+ require 'react/component/dsl_instance_methods'
34
+ require 'react/component/should_component_update'
35
+ require 'react/component/tags'
36
+ require 'react/component/base'
37
+ require 'react/element'
38
+ require 'react/event'
39
+ require 'react/api'
40
+ require 'react/rendering_context'
41
+ require 'react/state'
42
+ require 'react/object'
43
+ require 'react/ext/opal-jquery/element'
44
+ require 'reactive-ruby/isomorphic_helpers'
45
+ require 'rails-helpers/top_level_rails_component'
46
+ require 'reactive-ruby/version'
47
+ module Hyperloop
48
+ class Component
49
+ def self.inherited(child)
50
+ child.include(Mixin)
51
+ end
52
+ end
53
+ end
54
+ React::Component.deprecation_warning(
55
+ 'component.rb',
56
+ "Requiring 'hyper-react' is deprecated. Use gem 'hyper-component', and require 'hyper-component' instead."
57
+ ) unless defined? Hyperloop::Component::VERSION
58
+ else
6
59
  require 'opal'
7
- Opal.append_path(File.expand_path('../', __FILE__).untaint)
60
+
61
+ require 'hyper-store'
62
+ require 'opal-activesupport'
63
+ require 'reactive-ruby/version'
64
+ require 'reactive-ruby/rails' if defined?(Rails)
65
+ require 'reactive-ruby/isomorphic_helpers'
66
+ require 'reactive-ruby/serializers'
67
+
68
+ Opal.append_path File.expand_path('../', __FILE__).untaint
69
+ require 'react/react-source'
8
70
  end
@@ -0,0 +1,75 @@
1
+ module React
2
+ class TopLevelRailsComponent
3
+ include Hyperloop::Component::Mixin
4
+
5
+ def self.search_path
6
+ @search_path ||= [Object]
7
+ end
8
+
9
+ export_component
10
+
11
+ param :component_name
12
+ param :controller
13
+ param :render_params
14
+
15
+ backtrace :off
16
+
17
+ def render
18
+ paths_searched = []
19
+ component = nil
20
+ if params.component_name.start_with?('::')
21
+ # if absolute path of component is given, look it up and fail if not found
22
+ paths_searched << params.component_name
23
+ component = begin
24
+ Object.const_get(params.component_name)
25
+ rescue NameError
26
+ nil
27
+ end
28
+ else
29
+ # if relative path is given, look it up like this
30
+ # 1) we check each path + controller-name + component-name
31
+ # 2) if we can't find it there we check each path + component-name
32
+ # if we can't find it we just try const_get
33
+ # so (assuming controller name is Home)
34
+ # ::Foo::Bar will only resolve to some component named ::Foo::Bar
35
+ # but Foo::Bar will check (in this order) ::Home::Foo::Bar, ::Components::Home::Foo::Bar, ::Foo::Bar, ::Components::Foo::Bar
36
+ self.class.search_path.each do |scope|
37
+ paths_searched << "#{scope.name}::#{params.controller}::#{params.component_name}"
38
+ component = begin
39
+ scope.const_get(params.controller, false).const_get(params.component_name, false)
40
+ rescue NameError
41
+ nil
42
+ end
43
+ break if component != nil
44
+ end
45
+ unless component
46
+ self.class.search_path.each do |scope|
47
+ paths_searched << "#{scope.name}::#{params.component_name}"
48
+ component = begin
49
+ scope.const_get(params.component_name, false)
50
+ rescue NameError
51
+ nil
52
+ end
53
+ break if component != nil
54
+ end
55
+ end
56
+ end
57
+ return React::RenderingContext.render(component, params.render_params) if component && component.method_defined?(:render)
58
+ raise "Could not find component class '#{params.component_name}' for params.controller '#{params.controller}' in any component directory. Tried [#{paths_searched.join(", ")}]"
59
+ end
60
+ end
61
+ end
62
+
63
+ class Module
64
+ def add_to_react_search_path(replace_search_path = nil)
65
+ if replace_search_path
66
+ React::TopLevelRailsComponent.search_path = [self]
67
+ elsif !React::TopLevelRailsComponent.search_path.include? self
68
+ React::TopLevelRailsComponent.search_path << self
69
+ end
70
+ end
71
+ end
72
+
73
+ module Components
74
+ add_to_react_search_path
75
+ end
@@ -0,0 +1,203 @@
1
+ require 'react/native_library'
2
+
3
+ module React
4
+ # Provides the internal mechanisms to interface between reactrb and native components
5
+ # the code will attempt to create a js component wrapper on any rb class that has a
6
+ # render (or possibly _render_wrapper) method. The mapping between rb and js components
7
+ # is kept in the @@component_classes hash.
8
+
9
+ # Also provides the mechanism to build react elements
10
+
11
+ # TOOO - the code to deal with components should be moved to a module that will be included
12
+ # in a class which will then create the JS component for that class. That module will then
13
+ # be included in React::Component, but can be used by any class wanting to become a react
14
+ # component (but without other DSL characteristics.)
15
+ class API
16
+ @@component_classes = {}
17
+
18
+ def self.import_native_component(opal_class, native_class)
19
+ opal_class.instance_variable_set("@native_import", true)
20
+ @@component_classes[opal_class] = native_class
21
+ end
22
+
23
+ def self.eval_native_react_component(name)
24
+ component = `eval(name)`
25
+ raise "#{name} is not defined" if `#{component} === undefined`
26
+ is_component_class = `#{component}.prototype !== undefined` &&
27
+ (`!!#{component}.prototype.isReactComponent` ||
28
+ `!!#{component}.prototype.render`)
29
+ is_functional_component = `typeof #{component} === "function"`
30
+ unless is_component_class || is_functional_component
31
+ raise 'does not appear to be a native react component'
32
+ end
33
+ component
34
+ end
35
+
36
+ def self.native_react_component?(name = nil)
37
+ return false unless name
38
+ eval_native_react_component(name)
39
+ rescue
40
+ nil
41
+ end
42
+
43
+ def self.create_native_react_class(type)
44
+ raise "Provided class should define `render` method" if !(type.method_defined? :render)
45
+ render_fn = (type.method_defined? :_render_wrapper) ? :_render_wrapper : :render
46
+ # this was hashing type.to_s, not sure why but .to_s does not work as it Foo::Bar::View.to_s just returns "View"
47
+ @@component_classes[type] ||= %x{
48
+ class extends React.Component {
49
+ constructor(props) {
50
+ super(props);
51
+ this.mixins = #{type.respond_to?(:native_mixins) ? type.native_mixins : `[]`};
52
+ this.statics = #{type.respond_to?(:static_call_backs) ? type.static_call_backs.to_n : `{}`};
53
+ this.state = {};
54
+ this.__opalInstanceInitializedState = false;
55
+ this.__opalInstanceSyncSetState = true;
56
+ this.__opalInstance = #{type.new(`this`)};
57
+ this.__opalInstanceInitializedState = true;
58
+ this.__opalInstanceSyncSetState = false;
59
+ }
60
+ static get displayName() {
61
+ return #{type.name};
62
+ }
63
+ static get defaultProps() {
64
+ return #{type.respond_to?(:default_props) ? type.default_props.to_n : `{}`};
65
+ }
66
+ static get propTypes() {
67
+ return #{type.respond_to?(:prop_types) ? type.prop_types.to_n : `{}`};
68
+ }
69
+ componentWillMount() {
70
+ if (#{type.method_defined? :component_will_mount}) {
71
+ this.__opalInstanceSyncSetState = true;
72
+ this.__opalInstance.$component_will_mount();
73
+ this.__opalInstanceSyncSetState = false;
74
+ }
75
+ }
76
+ componentDidMount() {
77
+ this.__opalInstance.is_mounted = true
78
+ if (#{type.method_defined? :component_did_mount}) {
79
+ this.__opalInstanceSyncSetState = false;
80
+ this.__opalInstance.$component_did_mount();
81
+ }
82
+ }
83
+ componentWillReceiveProps(next_props) {
84
+ if (#{type.method_defined? :component_will_receive_props}) {
85
+ this.__opalInstanceSyncSetState = true;
86
+ this.__opalInstance.$component_will_receive_props(Opal.Hash.$new(next_props));
87
+ this.__opalInstanceSyncSetState = false;
88
+ }
89
+ }
90
+ shouldComponentUpdate(next_props, next_state) {
91
+ if (#{type.method_defined? :should_component_update?}) {
92
+ this.__opalInstanceSyncSetState = false;
93
+ return this.__opalInstance["$should_component_update?"](Opal.Hash.$new(next_props), Opal.Hash.$new(next_state));
94
+ } else { return true; }
95
+ }
96
+ componentWillUpdate(next_props, next_state) {
97
+ if (#{type.method_defined? :component_will_update}) {
98
+ this.__opalInstanceSyncSetState = false;
99
+ this.__opalInstance.$component_will_update(Opal.Hash.$new(next_props), Opal.Hash.$new(next_state));
100
+ }
101
+ }
102
+ componentDidUpdate(prev_props, prev_state) {
103
+ if (#{type.method_defined? :component_did_update}) {
104
+ this.__opalInstanceSyncSetState = false;
105
+ this.__opalInstance.$component_did_update(Opal.Hash.$new(prev_props), Opal.Hash.$new(prev_state));
106
+ }
107
+ }
108
+ componentWillUnmount() {
109
+ this.__opalInstance.is_mounted = false;
110
+ if (#{type.method_defined? :component_will_unmount}) {
111
+ this.__opalInstanceSyncSetState = false;
112
+ this.__opalInstance.$component_will_unmount();
113
+ }
114
+ }
115
+ componentDidCatch(error, info) {
116
+ if (#{type.method_defined? :component_did_catch}) {
117
+ this.__opalInstanceSyncSetState = false;
118
+ this.__opalInstance.$component_did_catch(error, Opal.Hash.$new(info));
119
+ }
120
+ }
121
+ render() {
122
+ this.__opalInstanceSyncSetState = false;
123
+ return this.__opalInstance.$send(render_fn).$to_n();
124
+ }
125
+ }
126
+ }
127
+ end
128
+
129
+ def self.create_element(type, properties = {}, &block)
130
+ params = []
131
+
132
+ # Component Spec, Normal DOM, String or Native Component
133
+ ncc = @@component_classes[type]
134
+ if ncc
135
+ params << ncc
136
+ elsif type.is_a?(Class)
137
+ params << create_native_react_class(type)
138
+ elsif block_given? || React::Component::Tags::HTML_TAGS.include?(type)
139
+ params << type
140
+ elsif type.is_a?(String)
141
+ return React::Element.new(type)
142
+ else
143
+ raise "#{type} not implemented"
144
+ end
145
+
146
+ # Convert Passed in properties
147
+ properties = convert_props(properties)
148
+ params << properties.shallow_to_n
149
+
150
+ # Children Nodes
151
+ if block_given?
152
+ a = [yield].flatten
153
+ %x{
154
+ for(var i=0, l=a.length; i<l; i++) {
155
+ params.push(a[i].$to_n());
156
+ }
157
+ }
158
+ end
159
+ React::Element.new(`React.createElement.apply(null, #{params})`, type, properties, block)
160
+ end
161
+
162
+ def self.clear_component_class_cache
163
+ @@component_classes = {}
164
+ end
165
+
166
+ def self.convert_props(properties)
167
+ raise "Component parameters must be a hash. Instead you sent #{properties}" unless properties.is_a? Hash
168
+ props = {}
169
+ properties.each do |key, value|
170
+ if key == "class" || key == "class_name"
171
+ props["className"] = value
172
+ elsif ["style", "dangerously_set_inner_HTML"].include? key
173
+ props[lower_camelize(key)] = value.to_n
174
+ elsif key == 'ref' && value.is_a?(Proc)
175
+ props[key] = %x{
176
+ function(dom_node){
177
+ if (dom_node.__opalInstance !== undefined && dom_node.__opalInstance !== null) {
178
+ #{ value.call(`dom_node.__opalInstance`) };
179
+ } else if(ReactDOM.findDOMNode !== undefined && dom_node.nodeType === undefined) {
180
+ #{ value.call(`ReactDOM.findDOMNode(dom_node)`) };
181
+ } else {
182
+ #{ value.call(`dom_node`) };
183
+ }
184
+ }
185
+ }
186
+ elsif React::HASH_ATTRIBUTES.include?(key) && value.is_a?(Hash)
187
+ value.each { |k, v| props["#{key}-#{k.tr('_', '-')}"] = v.to_n }
188
+ else
189
+ props[React.html_attr?(lower_camelize(key)) ? lower_camelize(key) : key] = value
190
+ end
191
+ end
192
+ props
193
+ end
194
+
195
+ private
196
+
197
+ def self.lower_camelize(snake_cased_word)
198
+ words = snake_cased_word.split('_')
199
+ result = [words.first]
200
+ result.concat(words[1..-1].map {|word| word[0].upcase + word[1..-1] }).join('')
201
+ end
202
+ end
203
+ end