reactrb 0.8.8 → 0.9.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +24 -3
- data/.gitignore +3 -0
- data/.rubocop.yml +1154 -3
- data/.travis.yml +20 -0
- data/Appraisals +20 -0
- data/CHANGELOG.md +28 -3
- data/Gemfile +4 -5
- data/README.md +6 -9
- data/Rakefile +6 -1
- data/config.ru +7 -6
- data/gemfiles/opal_0.8_react_13.gemfile +13 -0
- data/gemfiles/opal_0.8_react_14.gemfile +13 -0
- data/gemfiles/opal_0.8_react_15.gemfile +13 -0
- data/gemfiles/opal_0.9_react_13.gemfile +13 -0
- data/gemfiles/opal_0.9_react_14.gemfile +13 -0
- data/gemfiles/opal_0.9_react_15.gemfile +13 -0
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +1 -1
- data/lib/rails-helpers/top_level_rails_component.rb +1 -1
- data/lib/react-sources/react-server.js +2 -0
- data/lib/react/api.rb +13 -12
- data/lib/react/children.rb +30 -0
- data/lib/react/component.rb +27 -46
- data/lib/react/component/class_methods.rb +28 -32
- data/lib/react/component/dsl_instance_methods.rb +4 -34
- data/lib/react/component/params.rb +6 -0
- data/lib/react/component/props_wrapper.rb +22 -27
- data/lib/react/component/should_component_update.rb +98 -0
- data/lib/react/component/tags.rb +45 -4
- data/lib/react/element.rb +26 -13
- data/lib/react/object.rb +15 -0
- data/lib/react/react-source.rb +9 -0
- data/lib/react/rendering_context.rb +97 -93
- data/lib/react/state.rb +27 -21
- data/lib/react/test.rb +16 -0
- data/lib/react/test/dsl.rb +17 -0
- data/lib/react/test/matchers/render_html_matcher.rb +49 -0
- data/lib/react/test/rspec.rb +15 -0
- data/lib/react/test/session.rb +46 -0
- data/lib/react/top_level.rb +50 -14
- data/lib/react/validator.rb +5 -5
- data/lib/reactive-ruby/isomorphic_helpers.rb +0 -7
- data/lib/reactive-ruby/version.rb +1 -1
- data/lib/reactrb.rb +14 -14
- data/lib/reactrb/deep-compare.rb +24 -0
- data/lib/sources/react-latest.js +2 -0
- data/lib/sources/react-v13.js +4 -1
- data/lib/sources/react-v14.js +3 -84
- data/lib/sources/react-v15.js +3 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +1 -1
- data/reactrb.gemspec +2 -3
- data/spec/react/children_spec.rb +76 -0
- data/spec/react/component/base_spec.rb +3 -7
- data/spec/react/component_spec.rb +181 -60
- data/spec/react/dsl_spec.rb +26 -19
- data/spec/react/element_spec.rb +16 -1
- data/spec/react/native_library_spec.rb +20 -0
- data/spec/react/opal_jquery_extensions_spec.rb +27 -0
- data/spec/react/param_declaration_spec.rb +47 -78
- data/spec/react/react_spec.rb +7 -9
- data/spec/react/state_spec.rb +29 -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 +100 -0
- data/spec/react/test/utils_spec.rb +45 -0
- data/spec/react/top_level_component_spec.rb +33 -5
- data/spec/react/tutorial/tutorial_spec.rb +5 -5
- data/spec/react/validator_spec.rb +10 -13
- data/spec/reactive-ruby/component_loader_spec.rb +3 -0
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +5 -4
- data/spec/spec_helper.rb +6 -3
- data/spec/support/react/spec_helpers.rb +9 -2
- metadata +47 -124
- data/example/examples/Gemfile +0 -7
- data/example/examples/app/basics.js.rb +0 -42
- data/example/examples/app/items.rb +0 -11
- data/example/examples/app/jquery.js +0 -5
- data/example/examples/app/nodes.rb +0 -61
- data/example/examples/app/react-router.js +0 -6
- data/example/examples/app/react_api_demo.rb +0 -29
- data/example/examples/app/rerendering.rb +0 -72
- data/example/examples/app/reuse.rb +0 -59
- data/example/examples/app/show.rb +0 -52
- data/example/examples/config.ru +0 -38
- data/example/rails-tutorial/.gitignore +0 -17
- data/example/rails-tutorial/Gemfile +0 -51
- data/example/rails-tutorial/README.rdoc +0 -28
- data/example/rails-tutorial/Rakefile +0 -6
- data/example/rails-tutorial/app/assets/images/.keep +0 -0
- data/example/rails-tutorial/app/assets/javascripts/application.rb +0 -15
- data/example/rails-tutorial/app/assets/stylesheets/application.css +0 -15
- data/example/rails-tutorial/app/controllers/application_controller.rb +0 -6
- data/example/rails-tutorial/app/controllers/concerns/.keep +0 -0
- data/example/rails-tutorial/app/controllers/home_controller.rb +0 -6
- data/example/rails-tutorial/app/helpers/application_helper.rb +0 -2
- data/example/rails-tutorial/app/mailers/.keep +0 -0
- data/example/rails-tutorial/app/models/.keep +0 -0
- data/example/rails-tutorial/app/models/concerns/.keep +0 -0
- data/example/rails-tutorial/app/views/components.rb +0 -3
- data/example/rails-tutorial/app/views/components/home/show.rb +0 -47
- data/example/rails-tutorial/app/views/layouts/application.html.erb +0 -14
- data/example/rails-tutorial/bin/bundle +0 -3
- data/example/rails-tutorial/bin/rails +0 -8
- data/example/rails-tutorial/bin/rake +0 -8
- data/example/rails-tutorial/bin/setup +0 -29
- data/example/rails-tutorial/bin/spring +0 -15
- data/example/rails-tutorial/config.ru +0 -4
- data/example/rails-tutorial/config/application.rb +0 -26
- data/example/rails-tutorial/config/boot.rb +0 -3
- data/example/rails-tutorial/config/database.yml +0 -25
- data/example/rails-tutorial/config/environment.rb +0 -5
- data/example/rails-tutorial/config/environments/development.rb +0 -41
- data/example/rails-tutorial/config/environments/production.rb +0 -79
- data/example/rails-tutorial/config/environments/test.rb +0 -42
- data/example/rails-tutorial/config/initializers/assets.rb +0 -11
- data/example/rails-tutorial/config/initializers/backtrace_silencers.rb +0 -7
- data/example/rails-tutorial/config/initializers/cookies_serializer.rb +0 -3
- data/example/rails-tutorial/config/initializers/filter_parameter_logging.rb +0 -4
- data/example/rails-tutorial/config/initializers/inflections.rb +0 -16
- data/example/rails-tutorial/config/initializers/mime_types.rb +0 -4
- data/example/rails-tutorial/config/initializers/session_store.rb +0 -3
- data/example/rails-tutorial/config/initializers/wrap_parameters.rb +0 -14
- data/example/rails-tutorial/config/locales/en.yml +0 -23
- data/example/rails-tutorial/config/routes.rb +0 -59
- data/example/rails-tutorial/config/secrets.yml +0 -22
- data/example/rails-tutorial/db/seeds.rb +0 -7
- data/example/rails-tutorial/lib/assets/.keep +0 -0
- data/example/rails-tutorial/lib/tasks/.keep +0 -0
- data/example/rails-tutorial/log/.keep +0 -0
- data/example/rails-tutorial/public/404.html +0 -67
- data/example/rails-tutorial/public/422.html +0 -67
- data/example/rails-tutorial/public/500.html +0 -66
- data/example/rails-tutorial/public/favicon.ico +0 -0
- data/example/rails-tutorial/public/robots.txt +0 -5
- data/example/rails-tutorial/test/controllers/.keep +0 -0
- data/example/rails-tutorial/test/fixtures/.keep +0 -0
- data/example/rails-tutorial/test/helpers/.keep +0 -0
- data/example/rails-tutorial/test/integration/.keep +0 -0
- data/example/rails-tutorial/test/mailers/.keep +0 -0
- data/example/rails-tutorial/test/models/.keep +0 -0
- data/example/rails-tutorial/test/test_helper.rb +0 -10
- data/example/rails-tutorial/vendor/assets/javascripts/.keep +0 -0
- data/example/rails-tutorial/vendor/assets/stylesheets/.keep +0 -0
- data/example/sinatra-tutorial/.DS_Store +0 -0
- data/example/sinatra-tutorial/Gemfile +0 -5
- data/example/sinatra-tutorial/README.md +0 -8
- data/example/sinatra-tutorial/_comments.json +0 -42
- data/example/sinatra-tutorial/app/example.rb +0 -290
- data/example/sinatra-tutorial/app/jquery.js +0 -5
- data/example/sinatra-tutorial/config.ru +0 -58
- data/example/sinatra-tutorial/public/base.css +0 -62
- data/example/todos/Gemfile +0 -11
- data/example/todos/README.md +0 -37
- data/example/todos/Rakefile +0 -8
- data/example/todos/app/application.rb +0 -22
- data/example/todos/app/components/app.react.rb +0 -61
- data/example/todos/app/components/footer.react.rb +0 -31
- data/example/todos/app/components/todo_item.react.rb +0 -46
- data/example/todos/app/components/todo_list.react.rb +0 -25
- data/example/todos/app/models/todo.rb +0 -19
- data/example/todos/config.ru +0 -14
- data/example/todos/index.html.haml +0 -16
- data/example/todos/spec/todo_spec.rb +0 -28
- data/example/todos/vendor/base.css +0 -410
- data/example/todos/vendor/bg.png +0 -0
- data/example/todos/vendor/jquery.js +0 -4
|
@@ -6,21 +6,21 @@ module React
|
|
|
6
6
|
def reactrb_component?
|
|
7
7
|
true
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
def backtrace(*args)
|
|
11
11
|
@dont_catch_exceptions = (args[0] == :none)
|
|
12
12
|
@backtrace_off = @dont_catch_exceptions || (args[0] == :off)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def process_exception(e, component, reraise =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
def process_exception(e, component, reraise = @dont_catch_exceptions)
|
|
16
|
+
unless @dont_catch_exceptions
|
|
17
|
+
message = ["Exception raised while rendering #{component}: #{e.message}"]
|
|
18
|
+
if e.backtrace && e.backtrace.length > 1 && !@backtrace_off
|
|
19
|
+
append_backtrace(message, e.backtrace)
|
|
20
|
+
end
|
|
21
|
+
`console.error(#{message.join("\n")})`
|
|
21
22
|
end
|
|
22
|
-
|
|
23
|
-
raise e if reraise || @dont_catch_exceptions
|
|
23
|
+
raise e if reraise
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def append_backtrace(message_array, backtrace)
|
|
@@ -29,17 +29,28 @@ module React
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def render(container = nil, params = {}, &block)
|
|
32
|
-
|
|
33
|
-
if container
|
|
32
|
+
if container
|
|
33
|
+
container = container.type if container.is_a? React::Element
|
|
34
|
+
define_method :render do
|
|
34
35
|
React::RenderingContext.render(container, params) { instance_eval(&block) if block }
|
|
35
|
-
else
|
|
36
|
-
instance_eval(&block)
|
|
37
36
|
end
|
|
37
|
+
else
|
|
38
|
+
define_method(:render) { instance_eval(&block) }
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
# method missing will assume the method is a class name, and will treat this a render of
|
|
43
|
+
# of the component, i.e. Foo::Bar.baz === Foo::Bar().baz
|
|
44
|
+
|
|
45
|
+
def method_missing(name, *args, &children)
|
|
46
|
+
Object.method_missing(name, *args, &children) unless args.empty?
|
|
47
|
+
React::RenderingContext.render(
|
|
48
|
+
self, class: React::Element.haml_class_name(name), &children
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
41
52
|
def validator
|
|
42
|
-
@validator ||= Validator.new(
|
|
53
|
+
@validator ||= Validator.new(props_wrapper)
|
|
43
54
|
end
|
|
44
55
|
|
|
45
56
|
def prop_types
|
|
@@ -70,10 +81,6 @@ module React
|
|
|
70
81
|
@props_wrapper ||= Class.new(PropsWrapper)
|
|
71
82
|
end
|
|
72
83
|
|
|
73
|
-
def define_param(name, param_type)
|
|
74
|
-
props_wrapper.define_param(name, param_type, self)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
84
|
def param(*args)
|
|
78
85
|
if args[0].is_a? Hash
|
|
79
86
|
options = args[0]
|
|
@@ -92,22 +99,11 @@ module React
|
|
|
92
99
|
end
|
|
93
100
|
end
|
|
94
101
|
|
|
95
|
-
def required_param(name, options = {})
|
|
96
|
-
React::Component.deprecation_warning "`required_param` is deprecated, use `param` instead."
|
|
97
|
-
validator.requires(name, options)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
alias_method :require_param, :required_param
|
|
101
|
-
|
|
102
|
-
def optional_param(name, options = {})
|
|
103
|
-
React::Component.deprecation_warning "`optional_param` is deprecated, use `param param_name: default_value` instead."
|
|
104
|
-
validator.optional(name, options)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
102
|
def collect_other_params_as(name)
|
|
108
103
|
validator.allow_undefined_props = true
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
validator_in_lexical_scope = validator
|
|
105
|
+
props_wrapper.define_method(name) do
|
|
106
|
+
@_all_others ||= validator_in_lexical_scope.undefined_props(props)
|
|
111
107
|
end
|
|
112
108
|
|
|
113
109
|
validator_in_lexial_scope = validator
|
|
@@ -1,44 +1,14 @@
|
|
|
1
|
+
require "react/children"
|
|
2
|
+
|
|
1
3
|
module React
|
|
2
4
|
module Component
|
|
3
5
|
module DslInstanceMethods
|
|
4
6
|
def children
|
|
5
|
-
|
|
6
|
-
nodes = []
|
|
7
|
-
else
|
|
8
|
-
nodes = [`#{@native}.props.children`].flatten
|
|
9
|
-
end
|
|
10
|
-
class << nodes
|
|
11
|
-
include Enumerable
|
|
12
|
-
|
|
13
|
-
def to_n
|
|
14
|
-
self
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def each(&block)
|
|
18
|
-
if block_given?
|
|
19
|
-
%x{
|
|
20
|
-
React.Children.forEach(#{self.to_n}, function(context){
|
|
21
|
-
#{yield React::Element.new(`context`)}
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
nil
|
|
25
|
-
else
|
|
26
|
-
Enumerator.new(`React.Children.count(#{self.to_n})`) do |y|
|
|
27
|
-
%x{
|
|
28
|
-
React.Children.forEach(#{self.to_n}, function(context){
|
|
29
|
-
#{y << Element.new(`context`)}
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
nodes
|
|
7
|
+
Children.new(`#{@native}.props.children`)
|
|
38
8
|
end
|
|
39
9
|
|
|
40
10
|
def params
|
|
41
|
-
@props_wrapper
|
|
11
|
+
@params ||= self.class.props_wrapper.new(self)
|
|
42
12
|
end
|
|
43
13
|
|
|
44
14
|
def props
|
|
@@ -7,16 +7,10 @@ module React
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
class PropsWrapper
|
|
10
|
-
attr_reader :
|
|
10
|
+
attr_reader :component
|
|
11
11
|
|
|
12
|
-
def self.define_param(name, param_type
|
|
13
|
-
owner.define_method("#{name}") do |*args, &block|
|
|
14
|
-
deprecated_params_method("#{name}", *args, &block)
|
|
15
|
-
end
|
|
12
|
+
def self.define_param(name, param_type)
|
|
16
13
|
if param_type == Observable
|
|
17
|
-
owner.define_method("#{name}!") do |*args|
|
|
18
|
-
deprecated_params_method("#{name}!", *args)
|
|
19
|
-
end
|
|
20
14
|
define_method("#{name}") do
|
|
21
15
|
value_for(name)
|
|
22
16
|
end
|
|
@@ -39,10 +33,8 @@ module React
|
|
|
39
33
|
end
|
|
40
34
|
else
|
|
41
35
|
define_method("#{name}") do
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
else
|
|
45
|
-
@processed_params[name] = if param_type.respond_to? :_react_param_conversion
|
|
36
|
+
fetch_from_cache(name) do
|
|
37
|
+
if param_type.respond_to? :_react_param_conversion
|
|
46
38
|
param_type._react_param_conversion props[name]
|
|
47
39
|
elsif param_type.is_a?(Array) &&
|
|
48
40
|
param_type[0].respond_to?(:_react_param_conversion)
|
|
@@ -57,21 +49,8 @@ module React
|
|
|
57
49
|
end
|
|
58
50
|
end
|
|
59
51
|
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
*@processed_params.collect do |key, value|
|
|
63
|
-
[key, value] if @props[key].equal? new_props[key] # `#{@props[key]} == #{new_props[key]}`
|
|
64
|
-
end.compact.flatten(1)
|
|
65
|
-
]
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def initialize(props, current_props_wrapper=nil)
|
|
69
|
-
@props = props || {}
|
|
70
|
-
@processed_params = if current_props_wrapper
|
|
71
|
-
current_props_wrapper.unchanged_processed_params(props)
|
|
72
|
-
else
|
|
73
|
-
{}
|
|
74
|
-
end
|
|
52
|
+
def initialize(component)
|
|
53
|
+
@component = component
|
|
75
54
|
end
|
|
76
55
|
|
|
77
56
|
def [](prop)
|
|
@@ -80,6 +59,22 @@ module React
|
|
|
80
59
|
|
|
81
60
|
private
|
|
82
61
|
|
|
62
|
+
def fetch_from_cache(name)
|
|
63
|
+
last, value = cache[name]
|
|
64
|
+
return value if last.equal?(props[name])
|
|
65
|
+
yield.tap do |value|
|
|
66
|
+
cache[name] = [props[name], value]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def cache
|
|
71
|
+
@cache ||= Hash.new { |h, k| h[k] = [] }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def props
|
|
75
|
+
component.props
|
|
76
|
+
end
|
|
77
|
+
|
|
83
78
|
def value_for(name)
|
|
84
79
|
self[name].instance_variable_get("@value") if self[name]
|
|
85
80
|
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module React
|
|
2
|
+
module Component
|
|
3
|
+
#
|
|
4
|
+
# React assumes all components should update, unless a component explicitly overrides
|
|
5
|
+
# the shouldComponentUpdate method. Reactrb does an explicit check doing a shallow
|
|
6
|
+
# compare of params, and using a timestamp to determine if state has changed.
|
|
7
|
+
|
|
8
|
+
# If needed components can provide their own #needs_update? method which will be
|
|
9
|
+
# passed the next params and state opal hashes.
|
|
10
|
+
|
|
11
|
+
# Attached to these hashes is a #changed? method that returns whether the hash contains
|
|
12
|
+
# changes as calculated by the base mechanism. This way implementations of #needs_update?
|
|
13
|
+
# can use the base comparison mechanism as needed.
|
|
14
|
+
|
|
15
|
+
# For example
|
|
16
|
+
# def needs_update?(next_params, next_state)
|
|
17
|
+
# # use a special comparison method
|
|
18
|
+
# return false if next_state.changed? || next_params.changed?
|
|
19
|
+
# # do some other special checks
|
|
20
|
+
# end
|
|
21
|
+
|
|
22
|
+
# Note that beginning in 0.9 we will use standard ruby compare on all params further reducing
|
|
23
|
+
# the need for needs_update?
|
|
24
|
+
#
|
|
25
|
+
module ShouldComponentUpdate
|
|
26
|
+
def should_component_update?(native_next_props, native_next_state)
|
|
27
|
+
State.set_state_context_to(self, false) do
|
|
28
|
+
next_params = Hash.new(native_next_props)
|
|
29
|
+
# rubocop:disable Style/DoubleNegation # we must return true/false to js land
|
|
30
|
+
if respond_to?(:needs_update?)
|
|
31
|
+
!!call_needs_update(next_params, native_next_state)
|
|
32
|
+
else
|
|
33
|
+
!!(props_changed?(next_params) || native_state_changed?(native_next_state))
|
|
34
|
+
end
|
|
35
|
+
# rubocop:enable Style/DoubleNegation
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# create opal hashes for next params and state, and attach
|
|
40
|
+
# the changed? method to each hash
|
|
41
|
+
|
|
42
|
+
def call_needs_update(next_params, native_next_state)
|
|
43
|
+
component = self
|
|
44
|
+
next_params.define_singleton_method(:changed?) do
|
|
45
|
+
component.props_changed?(self)
|
|
46
|
+
end
|
|
47
|
+
next_state = Hash.new(native_next_state)
|
|
48
|
+
next_state.define_singleton_method(:changed?) do
|
|
49
|
+
component.native_state_changed?(native_next_state)
|
|
50
|
+
end
|
|
51
|
+
needs_update?(next_params, next_state)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Whenever state changes, reactrb updates a timestamp on the state object.
|
|
55
|
+
# We can rapidly check for state changes comparing the incoming state time_stamp
|
|
56
|
+
# with the current time stamp.
|
|
57
|
+
|
|
58
|
+
# Different versions of react treat empty state differently, so we first
|
|
59
|
+
# convert anything that looks like an empty state to "false" for consistency.
|
|
60
|
+
|
|
61
|
+
# Then we test if one state is empty and the other is not, then we return false.
|
|
62
|
+
# Then we test if both states are empty we return true.
|
|
63
|
+
# If either state does not have a time stamp then we have to assume a change.
|
|
64
|
+
# Otherwise we check time stamps
|
|
65
|
+
|
|
66
|
+
# rubocop:disable Metrics/MethodLength # for effeciency we want this to be one method
|
|
67
|
+
def native_state_changed?(next_state)
|
|
68
|
+
%x{
|
|
69
|
+
var current_state = #{@native}.state
|
|
70
|
+
var normalized_next_state =
|
|
71
|
+
!#{next_state} || Object.keys(#{next_state}).length === 0 || #{nil} == #{next_state} ?
|
|
72
|
+
false : #{next_state}
|
|
73
|
+
var normalized_current_state =
|
|
74
|
+
!current_state || Object.keys(current_state).length === 0 || #{nil} == current_state ?
|
|
75
|
+
false : current_state
|
|
76
|
+
if (!normalized_current_state != !normalized_next_state) return(true)
|
|
77
|
+
if (!normalized_current_state && !normalized_next_state) return(false)
|
|
78
|
+
if (!normalized_current_state['***_state_updated_at-***'] ||
|
|
79
|
+
!normalized_next_state['***_state_updated_at-***']) return(true)
|
|
80
|
+
return (normalized_current_state['***_state_updated_at-***'] !=
|
|
81
|
+
normalized_next_state['***_state_updated_at-***'])
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
# rubocop:enable Metrics/MethodLength
|
|
85
|
+
|
|
86
|
+
# Do a shallow compare on the two hashes. Starting in 0.9 we will do a deep compare.
|
|
87
|
+
|
|
88
|
+
def props_changed?(next_params)
|
|
89
|
+
Component.deprecation_warning(
|
|
90
|
+
"Using shallow incoming params comparison.\n"\
|
|
91
|
+
'Do a require "reactrb/deep-compare, to get 0.9 behavior'
|
|
92
|
+
)
|
|
93
|
+
(props.keys.sort != next_params.keys.sort) ||
|
|
94
|
+
next_params.detect { |k, v| `#{v} != #{@native}.props[#{k}]` }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/react/component/tags.rb
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# class HtmlTagWrapper
|
|
2
|
+
# def initialize(name)
|
|
3
|
+
# @name = name
|
|
4
|
+
# end
|
|
5
|
+
# def to_s
|
|
6
|
+
# @name
|
|
7
|
+
# end
|
|
8
|
+
# def method_missing(n)
|
|
9
|
+
#
|
|
10
|
+
# end
|
|
11
|
+
|
|
12
|
+
|
|
1
13
|
module React
|
|
2
14
|
module Component
|
|
3
15
|
# contains the name of all HTML tags, and the mechanism to register a component
|
|
@@ -10,7 +22,10 @@ module React
|
|
|
10
22
|
main map mark menu menuitem meta meter nav noscript object ol optgroup option
|
|
11
23
|
output p param picture pre progress q rp rt ruby s samp script section select
|
|
12
24
|
small source span strong style sub summary sup table tbody td textarea tfoot th
|
|
13
|
-
thead time title tr track u ul var video wbr)
|
|
25
|
+
thead time title tr track u ul var video wbr) +
|
|
26
|
+
# The SVG Tags
|
|
27
|
+
%w(circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline
|
|
28
|
+
radialGradient rect stop svg text tspan)
|
|
14
29
|
|
|
15
30
|
# note: any tag can end in _as_node but this is deprecated
|
|
16
31
|
|
|
@@ -26,18 +41,42 @@ module React
|
|
|
26
41
|
|
|
27
42
|
# define each predefined tag as an instance method
|
|
28
43
|
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
29
47
|
HTML_TAGS.each do |tag|
|
|
30
48
|
define_method(tag) do |*params, &children|
|
|
31
|
-
|
|
49
|
+
if tag == 'p'
|
|
50
|
+
if children || params.count == 0 || (params.count == 1 && params.first.is_a?(Hash))
|
|
51
|
+
React::RenderingContext.render(tag, *params, &children)
|
|
52
|
+
else
|
|
53
|
+
Kernel.p(*params)
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
React::RenderingContext.render(tag, *params, &children)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
if tag != :div
|
|
60
|
+
alias_method tag.upcase, tag
|
|
61
|
+
const_set tag.upcase, tag
|
|
62
|
+
else
|
|
63
|
+
alias_method tag.upcase, tag
|
|
64
|
+
#const_set tag.upcase, React.create_element(tag)
|
|
65
|
+
#Object.const_set tag.upcase, Class.new(HtmlTagWrapper)
|
|
32
66
|
end
|
|
33
|
-
alias_method tag.upcase, tag
|
|
34
|
-
const_set tag.upcase, tag
|
|
35
67
|
# handle deprecated _as_node style
|
|
36
68
|
define_method("#{tag}_as_node") do |*params, &children|
|
|
37
69
|
React::RenderingContext.build_only(tag, *params, &children)
|
|
38
70
|
end
|
|
39
71
|
end
|
|
40
72
|
|
|
73
|
+
def self.html_tag_class_for(tag)
|
|
74
|
+
downcased_tag = tag.downcase
|
|
75
|
+
if tag =~ /[A-Z]+/ && HTML_TAGS.include?(downcased_tag)
|
|
76
|
+
Object.const_set tag, React.create_element(downcased_tag)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
41
80
|
# use method_missing to look up component names in the form of "Foo(..)"
|
|
42
81
|
# where there is no preceeding scope.
|
|
43
82
|
|
|
@@ -92,6 +131,8 @@ module React
|
|
|
92
131
|
|
|
93
132
|
def lookup_const(name)
|
|
94
133
|
return nil unless name =~ /^[A-Z]/
|
|
134
|
+
#html_tag = React::Component::Tags.html_tag_class(name)
|
|
135
|
+
#return html_tag if html_tag
|
|
95
136
|
scopes = self.class.name.to_s.split('::').inject([Module]) do |nesting, next_const|
|
|
96
137
|
nesting + [nesting.last.const_get(next_const)]
|
|
97
138
|
end.reverse
|
data/lib/react/element.rb
CHANGED
|
@@ -36,7 +36,7 @@ module React
|
|
|
36
36
|
|
|
37
37
|
def on(*event_names, &block)
|
|
38
38
|
event_names.each { |event_name| merge_event_prop!(event_name, &block) }
|
|
39
|
-
@native = `React.cloneElement(#{to_n}, #{properties.
|
|
39
|
+
@native = `React.cloneElement(#{to_n}, #{properties.shallow_to_n})`
|
|
40
40
|
self
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -44,15 +44,14 @@ module React
|
|
|
44
44
|
# Used for elements that are not yet in DOM, i.e. they are provided as children
|
|
45
45
|
# or they have been explicitly removed from the rendering context using the delete method.
|
|
46
46
|
|
|
47
|
-
def render(props = {})
|
|
47
|
+
def render(props = {}, &new_block)
|
|
48
48
|
if props.empty?
|
|
49
49
|
React::RenderingContext.render(self)
|
|
50
50
|
else
|
|
51
|
+
props = API.convert_props(props)
|
|
51
52
|
React::RenderingContext.render(
|
|
52
|
-
Element.new(
|
|
53
|
-
|
|
54
|
-
type, properties.merge(props), block
|
|
55
|
-
)
|
|
53
|
+
Element.new(`React.cloneElement(#{to_n}, #{props.shallow_to_n})`,
|
|
54
|
+
type, properties.merge(props), block),
|
|
56
55
|
)
|
|
57
56
|
end
|
|
58
57
|
end
|
|
@@ -78,20 +77,34 @@ module React
|
|
|
78
77
|
# params may be provide to each class (but typically only to the last for easy reading.)
|
|
79
78
|
|
|
80
79
|
def method_missing(class_name, args = {}, &new_block)
|
|
81
|
-
|
|
82
|
-
new_props = properties.dup
|
|
83
|
-
new_props[:class] = "\
|
|
84
|
-
#{class_name} #{new_props[:class]} #{args.delete(:class)} #{args.delete(:className)}\
|
|
85
|
-
".split(' ').uniq.join(' ')
|
|
86
|
-
new_props.merge! args
|
|
80
|
+
return dup.render.method_missing(class_name, args, &new_block) unless rendered?
|
|
87
81
|
React::RenderingContext.replace(
|
|
88
82
|
self,
|
|
89
|
-
RenderingContext.build
|
|
83
|
+
RenderingContext.build do
|
|
84
|
+
RenderingContext.render(type, build_new_properties(class_name, args), &new_block)
|
|
85
|
+
end
|
|
90
86
|
)
|
|
91
87
|
end
|
|
92
88
|
|
|
89
|
+
def rendered?
|
|
90
|
+
React::RenderingContext.rendered? self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.haml_class_name(class_name)
|
|
94
|
+
class_name.gsub(/__|_/, '__' => '_', '_' => '-')
|
|
95
|
+
end
|
|
96
|
+
|
|
93
97
|
private
|
|
94
98
|
|
|
99
|
+
def build_new_properties(class_name, args)
|
|
100
|
+
class_name = self.class.haml_class_name(class_name)
|
|
101
|
+
new_props = properties.dup
|
|
102
|
+
new_props[:className] = "\
|
|
103
|
+
#{class_name} #{new_props[:className]} #{args.delete(:class)} #{args.delete(:className)}\
|
|
104
|
+
".split(' ').uniq.join(' ')
|
|
105
|
+
new_props.merge! args
|
|
106
|
+
end
|
|
107
|
+
|
|
95
108
|
# built in events, events going to native components, and events going to reactrb
|
|
96
109
|
|
|
97
110
|
# built in events will have their event param translated to the Event wrapper
|