hyper-react 0.12.7 → 0.99.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +48 -34
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +5 -6
- data/README.md +47 -98
- data/Rakefile +6 -28
- data/hyper-react.gemspec +36 -43
- data/lib/hyper-react.rb +4 -73
- data/lib/react/version.rb +3 -0
- metadata +91 -249
- data/.codeclimate.yml +0 -27
- data/.rubocop.yml +0 -1159
- data/.travis.yml +0 -62
- data/Appraisals +0 -31
- data/CHANGELOG.md +0 -143
- data/LICENSE +0 -19
- data/UPGRADING.md +0 -24
- data/component-name-lookup.md +0 -145
- data/config.ru +0 -26
- data/gemfiles/opal_0.10_react_13.gemfile +0 -15
- data/gemfiles/opal_0.10_react_14.gemfile +0 -15
- data/gemfiles/opal_0.10_react_15.gemfile +0 -15
- data/gemfiles/opal_0.8_react_13.gemfile +0 -15
- data/gemfiles/opal_0.8_react_14.gemfile +0 -15
- data/gemfiles/opal_0.8_react_15.gemfile +0 -15
- data/gemfiles/opal_0.9_react_13.gemfile +0 -15
- data/gemfiles/opal_0.9_react_14.gemfile +0 -15
- data/gemfiles/opal_0.9_react_15.gemfile +0 -15
- data/gemfiles/opal_master_react_15.gemfile +0 -16
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +0 -3
- data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +0 -2
- data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +0 -6
- data/lib/generators/reactive_ruby/test_app/templates/script/rails +0 -5
- data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +0 -13
- data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +0 -11
- data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +0 -14
- 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 +0 -111
- data/lib/rails-helpers/top_level_rails_component.rb +0 -54
- data/lib/react-sources/react-server.js +0 -2
- data/lib/react/api.rb +0 -173
- data/lib/react/callbacks.rb +0 -41
- data/lib/react/children.rb +0 -30
- data/lib/react/component.rb +0 -168
- data/lib/react/component/api.rb +0 -50
- data/lib/react/component/base.rb +0 -13
- data/lib/react/component/class_methods.rb +0 -189
- data/lib/react/component/dsl_instance_methods.rb +0 -23
- data/lib/react/component/params.rb +0 -6
- data/lib/react/component/props_wrapper.rb +0 -78
- data/lib/react/component/should_component_update.rb +0 -94
- data/lib/react/component/tags.rb +0 -129
- data/lib/react/config.rb +0 -5
- data/lib/react/config/client.rb.erb +0 -19
- data/lib/react/config/server.rb +0 -23
- data/lib/react/element.rb +0 -169
- data/lib/react/event.rb +0 -76
- data/lib/react/ext/hash.rb +0 -9
- data/lib/react/ext/opal-jquery/element.rb +0 -26
- data/lib/react/ext/string.rb +0 -8
- data/lib/react/hash.rb +0 -13
- data/lib/react/native_library.rb +0 -87
- data/lib/react/object.rb +0 -15
- data/lib/react/react-source-browser.rb +0 -3
- data/lib/react/react-source-server.rb +0 -3
- data/lib/react/react-source.rb +0 -20
- data/lib/react/ref_callback.rb +0 -31
- data/lib/react/rendering_context.rb +0 -144
- data/lib/react/server.rb +0 -23
- data/lib/react/state_wrapper.rb +0 -23
- data/lib/react/test.rb +0 -16
- data/lib/react/test/dsl.rb +0 -17
- data/lib/react/test/matchers/render_html_matcher.rb +0 -56
- data/lib/react/test/rspec.rb +0 -15
- data/lib/react/test/session.rb +0 -37
- data/lib/react/test/utils.rb +0 -25
- data/lib/react/top_level.rb +0 -118
- data/lib/react/top_level_render.rb +0 -29
- data/lib/react/validator.rb +0 -136
- data/lib/reactive-ruby/component_loader.rb +0 -50
- data/lib/reactive-ruby/isomorphic_helpers.rb +0 -212
- data/lib/reactive-ruby/rails.rb +0 -7
- data/lib/reactive-ruby/rails/component_mount.rb +0 -46
- data/lib/reactive-ruby/rails/controller_helper.rb +0 -15
- data/lib/reactive-ruby/rails/railtie.rb +0 -33
- data/lib/reactive-ruby/serializers.rb +0 -15
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +0 -42
- data/lib/reactive-ruby/version.rb +0 -3
- data/lib/reactrb/auto-import.rb +0 -27
- data/lib/reactrb/deep-compare.rb +0 -24
- data/lib/reactrb/new-event-name-convention.rb +0 -11
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/path_release_steps.md +0 -9
- data/spec/controller_helper_spec.rb +0 -34
- data/spec/index.html.erb +0 -11
- data/spec/react/callbacks_spec.rb +0 -138
- data/spec/react/children_spec.rb +0 -76
- data/spec/react/component/base_spec.rb +0 -32
- data/spec/react/component_spec.rb +0 -884
- data/spec/react/dsl_spec.rb +0 -303
- data/spec/react/element_spec.rb +0 -136
- data/spec/react/event_spec.rb +0 -24
- data/spec/react/native_library_spec.rb +0 -322
- data/spec/react/observable_spec.rb +0 -42
- data/spec/react/opal_jquery_extensions_spec.rb +0 -68
- data/spec/react/param_declaration_spec.rb +0 -269
- data/spec/react/react_spec.rb +0 -215
- data/spec/react/refs_callback_spec.rb +0 -56
- data/spec/react/server_spec.rb +0 -25
- data/spec/react/state_spec.rb +0 -55
- data/spec/react/test/dsl_spec.rb +0 -43
- data/spec/react/test/matchers/render_html_matcher_spec.rb +0 -83
- data/spec/react/test/rspec_spec.rb +0 -62
- data/spec/react/test/session_spec.rb +0 -88
- data/spec/react/test/utils_spec.rb +0 -28
- data/spec/react/top_level_component_spec.rb +0 -101
- data/spec/react/tutorial/tutorial_spec.rb +0 -36
- data/spec/react/validator_spec.rb +0 -124
- data/spec/reactive-ruby/component_loader_spec.rb +0 -77
- data/spec/reactive-ruby/isomorphic_helpers_spec.rb +0 -160
- data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +0 -10
- data/spec/reactive-ruby/rails/component_mount_spec.rb +0 -66
- data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +0 -35
- data/spec/spec_helper.rb +0 -149
- data/spec/support/react/spec_helpers.rb +0 -44
- data/spec/vendor/es5-shim.min.js +0 -6
- data/spec/vendor/jquery-2.2.4.min.js +0 -4
@@ -1,23 +0,0 @@
|
|
1
|
-
require "react/children"
|
2
|
-
|
3
|
-
module React
|
4
|
-
module Component
|
5
|
-
module DslInstanceMethods
|
6
|
-
def children
|
7
|
-
Children.new(`#{@native}.props.children`)
|
8
|
-
end
|
9
|
-
|
10
|
-
def params
|
11
|
-
@params ||= self.class.props_wrapper.new(self)
|
12
|
-
end
|
13
|
-
|
14
|
-
def props
|
15
|
-
Hash.new(`#{@native}.props`)
|
16
|
-
end
|
17
|
-
|
18
|
-
def refs
|
19
|
-
Hash.new(`#{@native}.refs`)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
module React
|
2
|
-
module Component
|
3
|
-
|
4
|
-
class PropsWrapper
|
5
|
-
attr_reader :component
|
6
|
-
|
7
|
-
def self.define_param(name, param_type)
|
8
|
-
if param_type == Observable
|
9
|
-
define_method("#{name}") do
|
10
|
-
value_for(name)
|
11
|
-
end
|
12
|
-
define_method("#{name}!") do |*args|
|
13
|
-
current_value = value_for(name)
|
14
|
-
if args.count > 0
|
15
|
-
props[name].call args[0]
|
16
|
-
current_value
|
17
|
-
else
|
18
|
-
# rescue in case we in middle of render... What happens during a
|
19
|
-
# render that causes exception?
|
20
|
-
# Where does `dont_update_state` come from?
|
21
|
-
props[name].call current_value unless @dont_update_state rescue nil
|
22
|
-
props[name]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
elsif param_type == Proc
|
26
|
-
define_method("#{name}") do |*args, &block|
|
27
|
-
props[name].call(*args, &block) if props[name]
|
28
|
-
end
|
29
|
-
else
|
30
|
-
define_method("#{name}") do
|
31
|
-
fetch_from_cache(name) do
|
32
|
-
if param_type.respond_to? :_react_param_conversion
|
33
|
-
param_type._react_param_conversion props[name], nil
|
34
|
-
elsif param_type.is_a?(Array) &&
|
35
|
-
param_type[0].respond_to?(:_react_param_conversion)
|
36
|
-
props[name].collect do |param|
|
37
|
-
param_type[0]._react_param_conversion param, nil
|
38
|
-
end
|
39
|
-
else
|
40
|
-
props[name]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def initialize(component)
|
48
|
-
@component = component
|
49
|
-
end
|
50
|
-
|
51
|
-
def [](prop)
|
52
|
-
props[prop]
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def fetch_from_cache(name)
|
58
|
-
last, value = cache[name]
|
59
|
-
return value if last.equal?(props[name])
|
60
|
-
yield.tap do |value|
|
61
|
-
cache[name] = [props[name], value]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def cache
|
66
|
-
@cache ||= Hash.new { |h, k| h[k] = [] }
|
67
|
-
end
|
68
|
-
|
69
|
-
def props
|
70
|
-
component.props
|
71
|
-
end
|
72
|
-
|
73
|
-
def value_for(name)
|
74
|
-
self[name].instance_variable_get("@value") if self[name]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,94 +0,0 @@
|
|
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
|
-
(props.keys.sort != next_params.keys.sort) ||
|
90
|
-
next_params.detect { |k, v| `#{v} != #{@native}.props[#{k}]` }
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
data/lib/react/component/tags.rb
DELETED
@@ -1,129 +0,0 @@
|
|
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
|
-
|
13
|
-
module React
|
14
|
-
module Component
|
15
|
-
# contains the name of all HTML tags, and the mechanism to register a component
|
16
|
-
# class as a new tag
|
17
|
-
module Tags
|
18
|
-
HTML_TAGS = %w(a abbr address area article aside audio b base bdi bdo big blockquote body br
|
19
|
-
button canvas caption cite code col colgroup data datalist dd del details dfn
|
20
|
-
dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
|
21
|
-
h6 head header hr html i iframe img input ins kbd keygen label legend li link
|
22
|
-
main map mark menu menuitem meta meter nav noscript object ol optgroup option
|
23
|
-
output p param picture pre progress q rp rt ruby s samp script section select
|
24
|
-
small source span strong style sub summary sup table tbody td textarea tfoot th
|
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)
|
29
|
-
|
30
|
-
# the present method is retained as a legacy behavior
|
31
|
-
|
32
|
-
def present(component, *params, &children)
|
33
|
-
React::RenderingContext.render(component, *params, &children)
|
34
|
-
end
|
35
|
-
|
36
|
-
# define each predefined tag as an instance method
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
HTML_TAGS.each do |tag|
|
42
|
-
define_method(tag) do |*params, &children|
|
43
|
-
if tag == 'p'
|
44
|
-
if children || params.count == 0 || (params.count == 1 && params.first.is_a?(Hash))
|
45
|
-
React::RenderingContext.render(tag, *params, &children)
|
46
|
-
else
|
47
|
-
Kernel.p(*params)
|
48
|
-
end
|
49
|
-
else
|
50
|
-
React::RenderingContext.render(tag, *params, &children)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
if tag != :div
|
54
|
-
alias_method tag.upcase, tag
|
55
|
-
const_set tag.upcase, tag
|
56
|
-
else
|
57
|
-
alias_method tag.upcase, tag
|
58
|
-
#const_set tag.upcase, React.create_element(tag)
|
59
|
-
#Object.const_set tag.upcase, Class.new(HtmlTagWrapper)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.html_tag_class_for(tag)
|
64
|
-
downcased_tag = tag.downcase
|
65
|
-
if tag =~ /[A-Z]+/ && HTML_TAGS.include?(downcased_tag)
|
66
|
-
Object.const_set tag, React.create_element(downcased_tag)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# use method_missing to look up component names in the form of "Foo(..)"
|
71
|
-
# where there is no preceeding scope.
|
72
|
-
|
73
|
-
def method_missing(name, *params, &children)
|
74
|
-
component = find_component(name)
|
75
|
-
return React::RenderingContext.render(component, *params, &children) if component
|
76
|
-
Object.method_missing(name, *params, &children)
|
77
|
-
end
|
78
|
-
|
79
|
-
# install methods with the same name as the component in the parent class/module
|
80
|
-
# thus component names in the form Foo::Bar(...) will work
|
81
|
-
|
82
|
-
class << self
|
83
|
-
def included(component)
|
84
|
-
name, parent = find_name_and_parent(component)
|
85
|
-
tag_names_module = Module.new do
|
86
|
-
define_method name do |*params, &children|
|
87
|
-
React::RenderingContext.render(component, *params, &children)
|
88
|
-
end
|
89
|
-
# handle deprecated _as_node style
|
90
|
-
define_method "#{name}_as_node" do |*params, &children|
|
91
|
-
React::RenderingContext.build_only(component, *params, &children)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
parent.extend(tag_names_module)
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
|
99
|
-
def find_name_and_parent(component)
|
100
|
-
split_name = component.name && component.name.split('::')
|
101
|
-
if split_name && split_name.length > 1
|
102
|
-
[split_name.last, split_name.inject([Module]) { |a, e| a + [a.last.const_get(e)] }[-2]]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def find_component(name)
|
110
|
-
component = lookup_const(name)
|
111
|
-
if component && !component.method_defined?(:render)
|
112
|
-
raise "#{name} does not appear to be a react component."
|
113
|
-
end
|
114
|
-
component
|
115
|
-
end
|
116
|
-
|
117
|
-
def lookup_const(name)
|
118
|
-
return nil unless name =~ /^[A-Z]/
|
119
|
-
#html_tag = React::Component::Tags.html_tag_class(name)
|
120
|
-
#return html_tag if html_tag
|
121
|
-
scopes = self.class.name.to_s.split('::').inject([Module]) do |nesting, next_const|
|
122
|
-
nesting + [nesting.last.const_get(next_const)]
|
123
|
-
end.reverse
|
124
|
-
scope = scopes.detect { |s| s.const_defined?(name) }
|
125
|
-
scope.const_get(name) if scope
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
data/lib/react/config.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
if RUBY_ENGINE == 'opal'
|
2
|
-
module React
|
3
|
-
module Config
|
4
|
-
extend self
|
5
|
-
def environment=(value)
|
6
|
-
raise "Environment cannot be configured at runtime."
|
7
|
-
end
|
8
|
-
|
9
|
-
def config
|
10
|
-
hash = %x{
|
11
|
-
Opal.hash({
|
12
|
-
environment: <%= '"' + React::Config.config[:environment] + '"' %>
|
13
|
-
})
|
14
|
-
}
|
15
|
-
hash
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/react/config/server.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
if RUBY_ENGINE != 'opal'
|
2
|
-
module React
|
3
|
-
module Config
|
4
|
-
extend self
|
5
|
-
def environment=(value)
|
6
|
-
config[:environment] = value
|
7
|
-
end
|
8
|
-
|
9
|
-
def config
|
10
|
-
@config ||= default_config
|
11
|
-
end
|
12
|
-
|
13
|
-
def default_config
|
14
|
-
{
|
15
|
-
environment: ENV['RACK_ENV'] || 'development'
|
16
|
-
}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
module Hyperloop
|
21
|
-
define_setting :prerendering, :on
|
22
|
-
end
|
23
|
-
end
|
data/lib/react/element.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
require 'react/ext/string'
|
2
|
-
|
3
|
-
module React
|
4
|
-
#
|
5
|
-
# Wraps the React Native element class
|
6
|
-
#
|
7
|
-
# adds the #on method to add event handlers to the element
|
8
|
-
#
|
9
|
-
# adds the #render method to place elements in the DOM and
|
10
|
-
# #delete (alias/deprecated #as_node) method to remove elements from the DOM
|
11
|
-
#
|
12
|
-
# handles the haml style class notation so that
|
13
|
-
# div.bar.blat becomes div(class: "bar blat")
|
14
|
-
# by using method missing
|
15
|
-
#
|
16
|
-
class Element
|
17
|
-
include Native
|
18
|
-
|
19
|
-
alias_native :element_type, :type
|
20
|
-
alias_native :props, :props
|
21
|
-
|
22
|
-
attr_reader :type
|
23
|
-
attr_reader :properties
|
24
|
-
attr_reader :block
|
25
|
-
|
26
|
-
attr_accessor :waiting_on_resources
|
27
|
-
|
28
|
-
def initialize(native_element, type = nil, properties = {}, block = nil)
|
29
|
-
@type = type
|
30
|
-
@properties = (`typeof #{properties} === 'undefined'` ? nil : properties) || {}
|
31
|
-
@block = block
|
32
|
-
@native = native_element
|
33
|
-
end
|
34
|
-
|
35
|
-
# Attach event handlers.
|
36
|
-
|
37
|
-
def on(*event_names, &block)
|
38
|
-
event_names.each { |event_name| merge_event_prop!(event_name, &block) }
|
39
|
-
@native = `React.cloneElement(#{to_n}, #{properties.shallow_to_n})`
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
# Render element into DOM in the current rendering context.
|
44
|
-
# Used for elements that are not yet in DOM, i.e. they are provided as children
|
45
|
-
# or they have been explicitly removed from the rendering context using the delete method.
|
46
|
-
|
47
|
-
def render(props = {}, &new_block)
|
48
|
-
if props.empty?
|
49
|
-
React::RenderingContext.render(self)
|
50
|
-
else
|
51
|
-
props = API.convert_props(props)
|
52
|
-
React::RenderingContext.render(
|
53
|
-
Element.new(`React.cloneElement(#{to_n}, #{props.shallow_to_n})`,
|
54
|
-
type, properties.merge(props), block),
|
55
|
-
)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Delete (remove) element from rendering context, the element may later be added back in
|
60
|
-
# using the render method.
|
61
|
-
|
62
|
-
def delete
|
63
|
-
React::RenderingContext.delete(self)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Deprecated version of delete method
|
67
|
-
|
68
|
-
def as_node
|
69
|
-
React::RenderingContext.as_node(self)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Any other method applied to an element will be treated as class name (haml style) thus
|
73
|
-
# div.foo.bar(id: :fred) is the same as saying div(class: "foo bar", id: :fred)
|
74
|
-
#
|
75
|
-
# single underscores become dashes, and double underscores become a single underscore
|
76
|
-
#
|
77
|
-
# params may be provide to each class (but typically only to the last for easy reading.)
|
78
|
-
|
79
|
-
def method_missing(class_name, args = {}, &new_block)
|
80
|
-
return dup.render.method_missing(class_name, args, &new_block) unless rendered?
|
81
|
-
React::RenderingContext.replace(
|
82
|
-
self,
|
83
|
-
RenderingContext.build do
|
84
|
-
RenderingContext.render(type, build_new_properties(class_name, args), &new_block)
|
85
|
-
end
|
86
|
-
)
|
87
|
-
end
|
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
|
-
|
97
|
-
private
|
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
|
-
|
108
|
-
# built in events, events going to native components, and events going to reactrb
|
109
|
-
|
110
|
-
# built in events will have their event param translated to the Event wrapper
|
111
|
-
# and the name will camelcased and have on prefixed, so :click becomes onClick.
|
112
|
-
#
|
113
|
-
# events emitting from native components are assumed to have the same camel case and
|
114
|
-
# on prefixed.
|
115
|
-
#
|
116
|
-
# events emitting from reactrb components will just have on_ prefixed. So
|
117
|
-
# :play_button_pushed attaches to the :on_play_button_pushed param
|
118
|
-
#
|
119
|
-
# in all cases the default name convention can be overriden by wrapping in <...> brackets.
|
120
|
-
# So on("<MyEvent>") will attach to the "MyEvent" param.
|
121
|
-
|
122
|
-
def merge_event_prop!(event_name, &block)
|
123
|
-
if event_name =~ /^<(.+)>$/
|
124
|
-
merge_component_event_prop! event_name.gsub(/^<(.+)>$/, '\1'), &block
|
125
|
-
elsif React::Event::BUILT_IN_EVENTS.include?(name = "on#{event_name.event_camelize}")
|
126
|
-
merge_built_in_event_prop! name, &block
|
127
|
-
elsif @type.instance_variable_get('@native_import')
|
128
|
-
merge_component_event_prop! name, &block
|
129
|
-
else
|
130
|
-
merge_deprecated_component_event_prop! event_name, &block
|
131
|
-
merge_component_event_prop! "on_#{event_name}", &block
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def merge_built_in_event_prop!(prop_name)
|
136
|
-
@properties.merge!(
|
137
|
-
prop_name => %x{
|
138
|
-
function(event){
|
139
|
-
return #{yield(React::Event.new(`event`))}
|
140
|
-
}
|
141
|
-
}
|
142
|
-
)
|
143
|
-
end
|
144
|
-
|
145
|
-
def merge_component_event_prop!(prop_name)
|
146
|
-
@properties.merge!(
|
147
|
-
prop_name => %x{
|
148
|
-
function(){
|
149
|
-
return #{yield(*Array(`arguments`))}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
)
|
153
|
-
end
|
154
|
-
|
155
|
-
def merge_deprecated_component_event_prop!(event_name)
|
156
|
-
prop_name = "_on#{event_name.event_camelize}"
|
157
|
-
fn = %x{function(){#{
|
158
|
-
React::Component.deprecation_warning(
|
159
|
-
type,
|
160
|
-
"In future releases React::Element#on('#{event_name}') will no longer respond "\
|
161
|
-
"to the '#{prop_name}' emitter.\n"\
|
162
|
-
"Rename your emitter param to 'on_#{event_name}' or use .on('<#{prop_name}>')"
|
163
|
-
)}
|
164
|
-
return #{yield(*Array(`arguments`))}
|
165
|
-
}}
|
166
|
-
@properties.merge!(prop_name => fn)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|