hyper-component 1.0.alpha1.1 → 1.0.alpha1.6
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/.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
|