hyper-component 1.0.alpha1.1 → 1.0.alpha1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/hyper-component.gemspec +6 -9
- data/lib/hyper-component.rb +10 -1
- data/lib/hyperstack/component.rb +78 -10
- data/lib/hyperstack/component/children.rb +1 -1
- data/lib/hyperstack/component/element.rb +93 -21
- data/lib/hyperstack/component/event.rb +1 -1
- data/lib/hyperstack/component/free_render.rb +21 -0
- data/lib/hyperstack/component/isomorphic_helpers.rb +13 -8
- data/lib/hyperstack/component/version.rb +1 -1
- data/lib/hyperstack/component/while_loading.rb +27 -0
- data/lib/hyperstack/ext/component/array.rb +20 -0
- data/lib/hyperstack/ext/component/element.rb +22 -8
- data/lib/hyperstack/ext/component/enumerable.rb +18 -0
- data/lib/hyperstack/ext/component/kernel.rb +7 -0
- data/lib/hyperstack/ext/component/string.rb +1 -1
- data/lib/hyperstack/internal/component.rb +7 -1
- data/lib/hyperstack/internal/component/class_methods.rb +84 -8
- data/lib/hyperstack/internal/component/haml.rb +3 -12
- data/lib/hyperstack/internal/component/instance_methods.rb +38 -5
- data/lib/hyperstack/internal/component/props_wrapper.rb +29 -9
- data/lib/hyperstack/internal/component/rails/component_mount.rb +12 -0
- data/lib/hyperstack/internal/component/rails/controller_helper.rb +20 -1
- data/lib/hyperstack/internal/component/rails/railtie.rb +3 -2
- data/lib/hyperstack/internal/component/rails/server_rendering/contextual_renderer.rb +5 -1
- data/lib/hyperstack/internal/component/rails/server_rendering/hyper_asset_container.rb +4 -2
- data/lib/hyperstack/internal/component/react_wrapper.rb +79 -62
- data/lib/hyperstack/internal/component/rendering_context.rb +95 -45
- data/lib/hyperstack/internal/component/rescue_wrapper.rb +40 -0
- data/lib/hyperstack/internal/component/should_component_update.rb +1 -1
- data/lib/hyperstack/internal/component/tags.rb +12 -3
- data/lib/hyperstack/internal/component/top_level_rails_component.rb +4 -0
- data/lib/hyperstack/internal/component/while_loading_wrapper.rb +29 -0
- data/lib/react/react-source.rb +2 -2
- metadata +50 -81
- data/Gemfile.lock +0 -363
@@ -18,16 +18,22 @@ module Hyperstack
|
|
18
18
|
def self.load_context(unique_id = nil, name = nil)
|
19
19
|
# can be called on the client to force re-initialization for testing purposes
|
20
20
|
if !unique_id || !@context || @context.unique_id != unique_id
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
message =
|
22
|
+
if on_opal_server?
|
23
|
+
`console.history = []` rescue nil
|
24
|
+
"************************ React Prerendering Context Initialized #{name} ***********************"
|
25
|
+
else
|
26
|
+
'************************ React Browser Context Initialized ****************************'
|
27
|
+
end
|
28
|
+
|
27
29
|
log(message)
|
30
|
+
|
28
31
|
@context = Context.new(unique_id)
|
29
32
|
end
|
30
|
-
|
33
|
+
|
34
|
+
# True is returned here because this method is evaluated by MiniRacer,
|
35
|
+
# and can cause TypeError: Converting circular structure to JSON to raise
|
36
|
+
true
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
@@ -139,7 +145,6 @@ module Hyperstack
|
|
139
145
|
|
140
146
|
def send_to_opal(method_name, *args)
|
141
147
|
return unless @ctx
|
142
|
-
args = [1] if args.length == 0
|
143
148
|
Hyperstack::Internal::Component::Rails::ComponentLoader.new(@ctx).load!
|
144
149
|
method_args = args.collect do |arg|
|
145
150
|
quarg = "#{arg}".tr('"', "'")
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Hyperstack
|
2
|
+
module Component
|
3
|
+
module WhileLoading
|
4
|
+
def __hyperstack_component_rescue_wrapper(child)
|
5
|
+
Hyperstack::Internal::Component::WhileLoadingWrapper(child: self, children_elements: child)
|
6
|
+
end
|
7
|
+
|
8
|
+
def resources_loading?
|
9
|
+
@__hyperstack_while_loading_waiting_on_resources
|
10
|
+
end
|
11
|
+
|
12
|
+
def resources_loaded?
|
13
|
+
!@__hyperstack_while_loading_waiting_on_resources
|
14
|
+
end
|
15
|
+
|
16
|
+
if Hyperstack::Component::IsomorphicHelpers.on_opal_client?
|
17
|
+
%x{
|
18
|
+
function onError(event) {
|
19
|
+
if (event.message.match(/^Uncaught NotQuiet: /)) event.preventDefault();
|
20
|
+
}
|
21
|
+
|
22
|
+
window.addEventListener('error', onError);
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# from Rails 6.0 activesupport. Remove once defined by Opal activesupport
|
2
|
+
class Array
|
3
|
+
# Removes and returns the elements for which the block returns a true value.
|
4
|
+
# If no block is given, an Enumerator is returned instead.
|
5
|
+
#
|
6
|
+
# numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
7
|
+
# odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
|
8
|
+
# numbers # => [0, 2, 4, 6, 8]
|
9
|
+
def extract!
|
10
|
+
return to_enum(:extract!) { size } unless block_given?
|
11
|
+
|
12
|
+
extracted_elements = []
|
13
|
+
|
14
|
+
reject! do |element|
|
15
|
+
extracted_elements << element if yield(element)
|
16
|
+
end
|
17
|
+
|
18
|
+
extracted_elements
|
19
|
+
end
|
20
|
+
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
Element.instance_eval do
|
2
2
|
def self.find(selector)
|
3
|
-
selector
|
4
|
-
selector.dom_node
|
5
|
-
|
6
|
-
|
7
|
-
end if `#{selector}.$dom_node !== undefined`
|
8
|
-
`$(#{selector})`
|
3
|
+
if `typeof #{selector}['$respond_to?'] == 'function'` && selector.respond_to?(:dom_node)
|
4
|
+
selector = selector.dom_node
|
5
|
+
end
|
6
|
+
`jQuery(#{selector})`
|
9
7
|
end
|
10
8
|
|
11
9
|
def self.[](selector)
|
@@ -37,7 +35,7 @@ Element.instance_eval do
|
|
37
35
|
# see react-rails documentation for more details
|
38
36
|
|
39
37
|
%x{
|
40
|
-
|
38
|
+
jQuery.fn.mount_components = function() {
|
41
39
|
this.each(function(e) { ReactRailsUJS.mountComponents(e[0]) })
|
42
40
|
return this;
|
43
41
|
}
|
@@ -45,4 +43,20 @@ Element.instance_eval do
|
|
45
43
|
Element.expose :mount_components
|
46
44
|
end
|
47
45
|
|
48
|
-
|
46
|
+
module Hyperstack
|
47
|
+
module Internal
|
48
|
+
module Component
|
49
|
+
module InstanceMethods
|
50
|
+
def set_jq(var)
|
51
|
+
->(val) { set(var).call(jQ[val]) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Object
|
59
|
+
def jQ
|
60
|
+
Element
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# from Rails 6.0 activesupport. Remove once defined by Opal activesupport
|
2
|
+
module Enumerable
|
3
|
+
INDEX_WITH_DEFAULT = Object.new
|
4
|
+
private_constant :INDEX_WITH_DEFAULT
|
5
|
+
def index_with(default = INDEX_WITH_DEFAULT)
|
6
|
+
if block_given?
|
7
|
+
result = {}
|
8
|
+
each { |elem| result[elem] = yield(elem) }
|
9
|
+
result
|
10
|
+
elsif default != INDEX_WITH_DEFAULT
|
11
|
+
result = {}
|
12
|
+
each { |elem| result[elem] = default }
|
13
|
+
result
|
14
|
+
else
|
15
|
+
to_enum(:index_with) { size if respond_to?(:size) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -20,6 +20,10 @@ module Hyperstack
|
|
20
20
|
true
|
21
21
|
end
|
22
22
|
|
23
|
+
def allow_deprecated_render_definition?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
23
27
|
def mounted_components
|
24
28
|
Hyperstack::Component.mounted_components.select { |c| c.class <= self }
|
25
29
|
end
|
@@ -38,17 +42,74 @@ module Hyperstack
|
|
38
42
|
backtrace[1..-1].each { |line| message_array << line }
|
39
43
|
end
|
40
44
|
|
45
|
+
def before_receive_props(*args, &block)
|
46
|
+
deprecation_warning "'before_receive_props' is deprecated. Use the 'before_new_params' macro instead."
|
47
|
+
before_new_params(*args, &block)
|
48
|
+
end
|
49
|
+
|
41
50
|
def render(container = nil, params = {}, &block)
|
51
|
+
Tags.included(self)
|
42
52
|
if container
|
43
|
-
container = container.
|
44
|
-
define_method
|
45
|
-
|
53
|
+
container = container.element_type if container.is_a? Hyperstack::Component::Element
|
54
|
+
define_method(:__hyperstack_component_render) do
|
55
|
+
__hyperstack_component_select_wrappers do
|
56
|
+
RenderingContext.render(container, params) do
|
57
|
+
instance_eval(&block) if block
|
58
|
+
end
|
59
|
+
end
|
46
60
|
end
|
47
61
|
else
|
48
|
-
define_method(:
|
62
|
+
define_method(:__hyperstack_component_render) do
|
63
|
+
__hyperstack_component_select_wrappers do
|
64
|
+
instance_eval(&block)
|
65
|
+
end
|
66
|
+
end
|
49
67
|
end
|
50
68
|
end
|
51
69
|
|
70
|
+
# def while_loading(*args, &block)
|
71
|
+
# __hyperstack_component_after_render_hook do |element|
|
72
|
+
# element.while_loading(*args) { |*aargs| instance_exec(*aargs, &block) }
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
|
76
|
+
def on(*args, &block)
|
77
|
+
__hyperstack_component_after_render_hook do |element|
|
78
|
+
element.on(*args) { |*aargs| instance_exec(*aargs, &block) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def rescues(*klasses, &block)
|
83
|
+
klasses = [StandardError] if klasses.empty?
|
84
|
+
__hyperstack_component_rescue_hook do |found, *args|
|
85
|
+
next [found, *args] if found || !klasses.detect { |klass| args[0].is_a? klass }
|
86
|
+
instance_exec(*args, &block)
|
87
|
+
[true, *args]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def before_render(*args, &block)
|
92
|
+
before_mount(*args, &block)
|
93
|
+
before_update(*args, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
def after_render(*args, &block)
|
97
|
+
after_mount(*args, &block)
|
98
|
+
after_update(*args, &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
# [:while_loading, :on].each do |method|
|
102
|
+
# define_method(method) do |*args, &block|
|
103
|
+
# @@alias_id ||= 0
|
104
|
+
# @@alias_id += 1
|
105
|
+
# alias_name = "__hyperstack_attach_post_render_hook_#{@@alias_id}"
|
106
|
+
# alias_method alias_name, :__hyperstack_attach_post_render_hook
|
107
|
+
# define_method(:__hyperstack_attach_post_render_hook) do |element|
|
108
|
+
# send(alias_name, element.while_loading(*args) { instance_eval(&block) })
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
# end
|
112
|
+
|
52
113
|
# method missing will assume the method is a class name, and will treat this a render of
|
53
114
|
# of the component, i.e. Foo::Bar.baz === Foo::Bar().baz
|
54
115
|
|
@@ -125,6 +186,10 @@ module Hyperstack
|
|
125
186
|
options[:default] ||= nil
|
126
187
|
options[:allow_nil] = true unless options.key?(:allow_nil)
|
127
188
|
end
|
189
|
+
if name == :class
|
190
|
+
name = :className
|
191
|
+
options[:alias] ||= :Class
|
192
|
+
end
|
128
193
|
if options[:default]
|
129
194
|
validator.optional(name, options)
|
130
195
|
else
|
@@ -138,14 +203,24 @@ module Hyperstack
|
|
138
203
|
|
139
204
|
alias other_params collect_other_params_as
|
140
205
|
alias others collect_other_params_as
|
206
|
+
alias other collect_other_params_as
|
207
|
+
alias opts collect_other_params_as
|
141
208
|
|
142
|
-
def
|
209
|
+
def fires(name, opts = {})
|
143
210
|
aka = opts[:alias] || "#{name}!"
|
144
|
-
name = name =~ /^<(.+)>$/
|
211
|
+
name = if name =~ /^<(.+)>$/
|
212
|
+
name.gsub(/^<(.+)>$/, '\1')
|
213
|
+
elsif Hyperstack::Component::Event::BUILT_IN_EVENTS.include?("on#{name.event_camelize}")
|
214
|
+
"on#{name.event_camelize}"
|
215
|
+
else
|
216
|
+
"on_#{name}"
|
217
|
+
end
|
145
218
|
validator.event(name)
|
146
219
|
define_method(aka) { |*args| props[name]&.call(*args) }
|
147
220
|
end
|
148
221
|
|
222
|
+
alias triggers fires
|
223
|
+
|
149
224
|
def define_state(*states, &block)
|
150
225
|
deprecation_warning "'define_state' is deprecated. Use the 'state' macro to declare states."
|
151
226
|
default_initial_value = (block && block.arity == 0) ? yield : nil
|
@@ -196,7 +271,8 @@ module Hyperstack
|
|
196
271
|
ReactWrapper.import_native_component(
|
197
272
|
self, ReactWrapper.eval_native_react_component(component_name)
|
198
273
|
)
|
199
|
-
|
274
|
+
render {}
|
275
|
+
#define_method(:render) {} # define a dummy render method - will never be called...
|
200
276
|
rescue Exception => e # rubocop:disable Lint/RescueException : we need to catch everything!
|
201
277
|
raise "#{self} cannot import '#{component_name}': #{e.message}."
|
202
278
|
# rubocop:enable Lint/RescueException
|
@@ -216,7 +292,7 @@ module Hyperstack
|
|
216
292
|
end
|
217
293
|
|
218
294
|
def to_n
|
219
|
-
ReactWrapper.
|
295
|
+
Hyperstack::Internal::Component::ReactWrapper.create_native_react_class(self)
|
220
296
|
end
|
221
297
|
end
|
222
298
|
end
|
@@ -27,7 +27,9 @@ module Hyperstack
|
|
27
27
|
Hyperstack::Internal::Component::RenderingContext.replace(
|
28
28
|
self,
|
29
29
|
Hyperstack::Internal::Component::RenderingContext.build do
|
30
|
-
Hyperstack::Internal::Component::RenderingContext.render(
|
30
|
+
Hyperstack::Internal::Component::RenderingContext.render(
|
31
|
+
element_type, @properties, args, class: haml_class_name(class_name), &new_block
|
32
|
+
)
|
31
33
|
end
|
32
34
|
)
|
33
35
|
end
|
@@ -39,17 +41,6 @@ module Hyperstack
|
|
39
41
|
def haml_class_name(class_name)
|
40
42
|
class_name.gsub(/__|_/, '__' => '_', '_' => '-')
|
41
43
|
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def build_new_properties(class_name, args)
|
46
|
-
class_name = haml_class_name(class_name)
|
47
|
-
new_props = @properties.dup
|
48
|
-
new_props[:className] = "\
|
49
|
-
#{class_name} #{new_props[:className]} #{args.delete(:class)} #{args.delete(:className)}\
|
50
|
-
".split(' ').uniq.join(' ')
|
51
|
-
new_props.merge! args
|
52
|
-
end
|
53
44
|
end
|
54
45
|
end
|
55
46
|
end
|
@@ -9,7 +9,7 @@ module Hyperstack
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def params
|
12
|
-
if @__hyperstack_component_params_wrapper.param_accessor_style
|
12
|
+
if [:hyperstack, :accessors].include? @__hyperstack_component_params_wrapper.param_accessor_style
|
13
13
|
raise "params are now directly accessible via instance variables.\n"\
|
14
14
|
' to access the legacy behavior add `param_accessor_style = :legacy` '\
|
15
15
|
"to your component class\n"\
|
@@ -23,18 +23,28 @@ module Hyperstack
|
|
23
23
|
Hash.new(`#{@__hyperstack_component_native}.props`)
|
24
24
|
end
|
25
25
|
|
26
|
-
def refs
|
27
|
-
Hash.new(`#{@__hyperstack_component_native}.refs`)
|
28
|
-
end
|
29
|
-
|
30
26
|
def dom_node
|
31
27
|
`ReactDOM.findDOMNode(#{self}.__hyperstack_component_native)` # react >= v0.15.0
|
32
28
|
end
|
33
29
|
|
30
|
+
def jq_node
|
31
|
+
::Element[dom_node]
|
32
|
+
end
|
33
|
+
|
34
34
|
def mounted?
|
35
35
|
`(#{self}.__hyperstack_component_is_mounted === undefined) ? false : #{self}.__hyperstack_component_is_mounted`
|
36
36
|
end
|
37
37
|
|
38
|
+
def pluralize(count, singular, plural = nil)
|
39
|
+
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
40
|
+
singular
|
41
|
+
else
|
42
|
+
plural || singular.pluralize
|
43
|
+
end
|
44
|
+
|
45
|
+
"#{count || 0} #{word}"
|
46
|
+
end
|
47
|
+
|
38
48
|
def force_update!
|
39
49
|
`#{self}.__hyperstack_component_native.forceUpdate()`
|
40
50
|
self
|
@@ -51,6 +61,29 @@ module Hyperstack
|
|
51
61
|
|
52
62
|
private
|
53
63
|
|
64
|
+
# can be overriden by the Router include
|
65
|
+
def __hyperstack_router_wrapper(&block)
|
66
|
+
->() { instance_eval(&block) }
|
67
|
+
end
|
68
|
+
|
69
|
+
# can be overriden by including WhileLoading include
|
70
|
+
def __hyperstack_component_rescue_wrapper(child)
|
71
|
+
if self.class.callbacks?(:__hyperstack_component_rescue_hook)
|
72
|
+
Hyperstack::Internal::Component::RescueWrapper(child: self, children_elements: child)
|
73
|
+
else
|
74
|
+
child.call
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def __hyperstack_component_select_wrappers(&block)
|
79
|
+
RescueWrapper.after_error_args = nil
|
80
|
+
__hyperstack_component_run_post_render_hooks(
|
81
|
+
__hyperstack_component_rescue_wrapper(
|
82
|
+
__hyperstack_router_wrapper(&block)
|
83
|
+
)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
54
87
|
def set_or_replace_state_or_prop(state_or_prop, method, &block)
|
55
88
|
raise "No native ReactComponent associated" unless @__hyperstack_component_native
|
56
89
|
`var state_prop_n = #{state_or_prop.shallow_to_n}`
|
@@ -9,7 +9,7 @@ module Hyperstack
|
|
9
9
|
def instance_var_name_for(name)
|
10
10
|
case Hyperstack.naming_convention
|
11
11
|
when :camelize_params
|
12
|
-
name.camelize
|
12
|
+
fix_suffix(name.camelize)
|
13
13
|
when :prefix_params
|
14
14
|
"_#{name}"
|
15
15
|
else
|
@@ -17,6 +17,17 @@ module Hyperstack
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
def fix_suffix(name)
|
21
|
+
return unless name
|
22
|
+
if name =~ /\?$/
|
23
|
+
name[0..-2] + '_q'
|
24
|
+
elsif name =~ /\!$/
|
25
|
+
name[0..-2] + '_b'
|
26
|
+
else
|
27
|
+
name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
20
31
|
def param_accessor_style(style = nil)
|
21
32
|
@param_accessor_style = style if style
|
22
33
|
@param_accessor_style ||=
|
@@ -37,17 +48,23 @@ module Hyperstack
|
|
37
48
|
end
|
38
49
|
|
39
50
|
def define_param(name, param_type, aka = nil)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
if param_accessor_style != :legacy || aka
|
52
|
+
meth_name = aka || name
|
53
|
+
var_name = fix_suffix(aka) || instance_var_name_for(name)
|
54
|
+
param_definitions[name] = lambda do |props|
|
55
|
+
@component.instance_variable_set :"@#{var_name}", val = fetch_from_cache(name, param_type, props)
|
56
|
+
next unless param_accessor_style == :accessors
|
57
|
+
`#{@component}[#{"$#{meth_name}"}] = function() { return #{val} }`
|
58
|
+
# @component.define_singleton_method(name) { val } if param_accessor_style == :accessors
|
59
|
+
end
|
60
|
+
return if %i[hyperstack accessors].include? param_accessor_style
|
44
61
|
end
|
45
62
|
if param_type == Proc
|
46
|
-
define_method(
|
63
|
+
define_method(name.to_sym) do |*args, &block|
|
47
64
|
props[name].call(*args, &block) if props[name]
|
48
65
|
end
|
49
66
|
else
|
50
|
-
define_method(
|
67
|
+
define_method(name.to_sym) do
|
51
68
|
fetch_from_cache(name, param_type, props)
|
52
69
|
end
|
53
70
|
end
|
@@ -56,7 +73,10 @@ module Hyperstack
|
|
56
73
|
def define_all_others(name)
|
57
74
|
var_name = instance_var_name_for(name)
|
58
75
|
param_definitions[name] = lambda do |props|
|
59
|
-
@component.instance_variable_set :"@#{var_name}", yield(props)
|
76
|
+
@component.instance_variable_set :"@#{var_name}", val = yield(props)
|
77
|
+
next unless param_accessor_style == :accessors
|
78
|
+
`#{@component}[#{"$#{name}"}] = function() { return #{val} }`
|
79
|
+
# @component.define_singleton_method(name) { val } if param_accessor_style == :accessors
|
60
80
|
end
|
61
81
|
define_method(name.to_sym) do
|
62
82
|
@_all_others_cache ||= yield(props)
|
@@ -70,7 +90,7 @@ module Hyperstack
|
|
70
90
|
|
71
91
|
def initialize(component, incoming = nil)
|
72
92
|
@component = component
|
73
|
-
return if param_accessor_style == :legacy
|
93
|
+
#return if param_accessor_style == :legacy
|
74
94
|
self.class.param_definitions.each_value do |initializer|
|
75
95
|
instance_exec(incoming || props, &initializer)
|
76
96
|
end
|