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.
- checksums.yaml +5 -5
- data/.codeclimate.yml +27 -0
- data/.gitignore +30 -37
- data/.rubocop.yml +1159 -0
- data/.travis.yml +32 -0
- data/Appraisals +31 -0
- data/CHANGELOG.md +143 -0
- data/DOCS.md +1515 -0
- data/Gemfile +2 -5
- data/LICENSE +19 -0
- data/README.md +5 -33
- data/Rakefile +25 -6
- data/UPGRADING.md +24 -0
- data/component-name-lookup.md +145 -0
- data/dciy.toml +3 -0
- data/dciy_prepare.sh +8 -0
- data/dciy_run.sh +10 -0
- data/hyper-react.gemspec +24 -18
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
- data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
- data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
- data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
- data/lib/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
- data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +117 -0
- data/lib/hyper-react.rb +66 -4
- data/lib/rails-helpers/top_level_rails_component.rb +75 -0
- data/lib/react/api.rb +203 -0
- data/lib/react/callbacks.rb +41 -0
- data/lib/react/children.rb +30 -0
- data/lib/react/component.rb +177 -0
- data/lib/react/component/api.rb +69 -0
- data/lib/react/component/base.rb +13 -0
- data/lib/react/component/class_methods.rb +181 -0
- data/lib/react/component/dsl_instance_methods.rb +23 -0
- data/lib/react/component/params.rb +6 -0
- data/lib/react/component/props_wrapper.rb +78 -0
- data/lib/react/component/should_component_update.rb +99 -0
- data/lib/react/component/tags.rb +108 -0
- data/lib/react/config.rb +5 -0
- data/lib/react/config/client.rb.erb +19 -0
- data/lib/react/config/server.rb +23 -0
- data/lib/react/element.rb +150 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/opal-jquery/element.rb +26 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/hash.rb +13 -0
- data/lib/react/native_library.rb +87 -0
- data/lib/react/object.rb +15 -0
- data/lib/react/react-source-browser.rb +3 -0
- data/lib/react/react-source-server.rb +3 -0
- data/lib/react/react-source.rb +16 -0
- data/lib/react/ref_callback.rb +31 -0
- data/lib/react/rendering_context.rb +146 -0
- data/lib/react/server.rb +19 -0
- data/lib/react/state_wrapper.rb +23 -0
- data/lib/react/test.rb +16 -0
- data/lib/react/test/dsl.rb +17 -0
- data/lib/react/test/matchers/render_html_matcher.rb +56 -0
- data/lib/react/test/rspec.rb +15 -0
- data/lib/react/test/session.rb +37 -0
- data/lib/react/test/utils.rb +71 -0
- data/lib/react/top_level.rb +110 -0
- data/lib/react/top_level_render.rb +28 -0
- data/lib/react/validator.rb +136 -0
- data/lib/reactive-ruby/component_loader.rb +43 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +235 -0
- data/lib/reactive-ruby/rails.rb +8 -0
- data/lib/reactive-ruby/rails/component_mount.rb +48 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +14 -0
- data/lib/reactive-ruby/rails/railtie.rb +20 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +41 -0
- data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +46 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/lib/reactrb/auto-import.rb +27 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- data/spec/controller_helper_spec.rb +35 -0
- data/spec/index.html.erb +11 -0
- data/spec/react/callbacks_spec.rb +142 -0
- data/spec/react/children_spec.rb +132 -0
- data/spec/react/component/base_spec.rb +36 -0
- data/spec/react/component_spec.rb +1073 -0
- data/spec/react/dsl_spec.rb +323 -0
- data/spec/react/element_spec.rb +132 -0
- data/spec/react/event_spec.rb +39 -0
- data/spec/react/native_library_spec.rb +387 -0
- data/spec/react/observable_spec.rb +31 -0
- data/spec/react/opal_jquery_extensions_spec.rb +68 -0
- data/spec/react/param_declaration_spec.rb +253 -0
- data/spec/react/react_spec.rb +278 -0
- data/spec/react/refs_callback_spec.rb +65 -0
- data/spec/react/server_spec.rb +25 -0
- data/spec/react/state_spec.rb +52 -0
- data/spec/react/test/dsl_spec.rb +43 -0
- data/spec/react/test/matchers/render_html_matcher_spec.rb +83 -0
- data/spec/react/test/rspec_spec.rb +62 -0
- data/spec/react/test/session_spec.rb +88 -0
- data/spec/react/test/utils_spec.rb +28 -0
- data/spec/react/top_level_component_spec.rb +103 -0
- data/spec/react/tutorial/tutorial_spec.rb +42 -0
- data/spec/react/validator_spec.rb +134 -0
- data/spec/reactive-ruby/component_loader_spec.rb +74 -0
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +157 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +17 -0
- data/spec/reactive-ruby/rails/component_mount_spec.rb +64 -0
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +39 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/test_app/README.md +24 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/config/manifest.js +3 -0
- data/spec/test_app/app/assets/images/.keep +0 -0
- data/spec/test_app/app/assets/javascripts/application.rb +7 -0
- data/spec/test_app/app/assets/javascripts/cable.js +13 -0
- data/spec/test_app/app/assets/javascripts/channels/.keep +0 -0
- data/spec/test_app/app/assets/javascripts/server_rendering.js +5 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/channels/application_cable/channel.rb +4 -0
- data/spec/test_app/app/channels/application_cable/connection.rb +4 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/controllers/concerns/.keep +0 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/jobs/application_job.rb +2 -0
- data/spec/test_app/app/mailers/application_mailer.rb +4 -0
- data/spec/test_app/app/models/application_record.rb +3 -0
- data/spec/test_app/app/models/concerns/.keep +0 -0
- data/spec/test_app/app/views/components.rb +11 -0
- data/spec/test_app/app/views/components/hello_world.rb +11 -0
- data/spec/test_app/app/views/components/todo.rb +14 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/app/views/layouts/explicit_layout.html.erb +0 -0
- data/spec/test_app/app/views/layouts/mailer.html.erb +13 -0
- data/spec/test_app/app/views/layouts/mailer.text.erb +1 -0
- data/spec/test_app/app/views/layouts/test_layout.html.erb +0 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/bin/setup +38 -0
- data/spec/test_app/bin/update +29 -0
- data/spec/test_app/bin/yarn +11 -0
- data/spec/test_app/config.ru +5 -0
- data/spec/test_app/config/application.rb +45 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/cable.yml +10 -0
- data/spec/test_app/config/database.yml +25 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +54 -0
- data/spec/test_app/config/environments/production.rb +91 -0
- data/spec/test_app/config/environments/test.rb +42 -0
- data/spec/test_app/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/test_app/config/initializers/assets.rb +14 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +33 -0
- data/spec/test_app/config/puma.rb +56 -0
- data/spec/test_app/config/routes.rb +3 -0
- data/spec/test_app/config/secrets.yml +32 -0
- data/spec/test_app/config/spring.rb +6 -0
- data/spec/test_app/db/development.sqlite3 +0 -0
- data/spec/test_app/db/schema.rb +15 -0
- data/spec/test_app/db/seeds.rb +7 -0
- data/spec/test_app/db/test.sqlite3 +0 -0
- data/spec/test_app/lib/assets/.keep +0 -0
- data/spec/test_app/log/.keep +0 -0
- data/spec/test_app/package.json +5 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/test_app/public/apple-touch-icon.png +0 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/vendor/es5-shim.min.js +7 -0
- data/spec/vendor/jquery-2.2.4.min.js +4 -0
- metadata +401 -61
- data/CODE_OF_CONDUCT.md +0 -49
- data/lib/react/version.rb +0 -3
|
File without changes
|
|
@@ -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
|
data/lib/hyper-react.rb
CHANGED
|
@@ -1,8 +1,70 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
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
|
|
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
|
-
|
|
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
|
data/lib/react/api.rb
ADDED
|
@@ -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
|