hyper-component 1.0.alpha1.2 → 1.0.alpha1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/Gemfile +5 -0
  4. data/hyper-component.gemspec +8 -16
  5. data/lib/hyper-component.rb +12 -1
  6. data/lib/hyperstack/component.rb +60 -10
  7. data/lib/hyperstack/component/children.rb +1 -1
  8. data/lib/hyperstack/component/element.rb +93 -21
  9. data/lib/hyperstack/component/event.rb +1 -1
  10. data/lib/hyperstack/component/free_render.rb +21 -0
  11. data/lib/hyperstack/component/isomorphic_helpers.rb +13 -10
  12. data/lib/hyperstack/component/version.rb +1 -1
  13. data/lib/hyperstack/component/while_loading.rb +27 -0
  14. data/lib/hyperstack/ext/component/array.rb +20 -0
  15. data/lib/hyperstack/ext/component/element.rb +22 -8
  16. data/lib/hyperstack/ext/component/enumerable.rb +18 -0
  17. data/lib/hyperstack/ext/component/kernel.rb +7 -0
  18. data/lib/hyperstack/ext/component/string.rb +1 -1
  19. data/lib/hyperstack/ext/component/time.rb +5 -0
  20. data/lib/hyperstack/internal/component.rb +7 -1
  21. data/lib/hyperstack/internal/component/class_methods.rb +68 -7
  22. data/lib/hyperstack/internal/component/haml.rb +3 -12
  23. data/lib/hyperstack/internal/component/instance_methods.rb +38 -1
  24. data/lib/hyperstack/internal/component/props_wrapper.rb +29 -10
  25. data/lib/hyperstack/internal/component/rails/component_mount.rb +12 -0
  26. data/lib/hyperstack/internal/component/rails/controller_helper.rb +20 -1
  27. data/lib/hyperstack/internal/component/rails/railtie.rb +3 -2
  28. data/lib/hyperstack/internal/component/rails/server_rendering/contextual_renderer.rb +5 -1
  29. data/lib/hyperstack/internal/component/rails/server_rendering/hyper_asset_container.rb +4 -2
  30. data/lib/hyperstack/internal/component/react_wrapper.rb +79 -62
  31. data/lib/hyperstack/internal/component/rendering_context.rb +95 -45
  32. data/lib/hyperstack/internal/component/rescue_wrapper.rb +40 -0
  33. data/lib/hyperstack/internal/component/should_component_update.rb +1 -1
  34. data/lib/hyperstack/internal/component/tags.rb +12 -3
  35. data/lib/hyperstack/internal/component/while_loading_wrapper.rb +29 -0
  36. data/lib/react/react-source.rb +2 -2
  37. metadata +56 -86
  38. data/Gemfile.lock +0 -363
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32f892af1c88068a155f6a7de78fe37ec32f157fe6e3e20d1a06db63501a43af
4
- data.tar.gz: 031e39966cb44433d836a82e563236b985b59def309a9bfb39107ac1cc151e08
3
+ metadata.gz: 52da8498aa33bf215fdb7f9ca2f8ec64bbded0e27e1592fae1fccff1d9fca729
4
+ data.tar.gz: 8eea0d1b5409774add2597e14242e6ca4164db00b935c7c62986bedb67ad283a
5
5
  SHA512:
6
- metadata.gz: 0ef39af06f446589c0b2ce1137d0403d0125c21657b857e7c3785921c800e9aaa1cb2975cd06e104de4bb45612bc510b0b3fe8ba0233dc68902b2d877bb1d430
7
- data.tar.gz: b3a8f74fecb413e0fa82eb7ce97de80123b7e67fd9da9b3a5d9bff2d6a7f287f03aad6a8b62703cb776b14fa0233c602964ca20e56d9225a774be11e59bae9c8
6
+ metadata.gz: 3d1796ae2f6a12698dd7545022f79cb9770a8e915f30d167ab87c2e967eee51b6c3e3a1062876d3851163ea3a6170cf3ea058030cf81696dee4d9ac7bb83db4c
7
+ data.tar.gz: 2fcb00144eac41c15a77cc77cb59677b665685791aa138f89d1bd540648201604bd5ee5572b8abaa592ac3e5d2af995850c1bb7fc420e6cac0117b1564ed6973
data/.gitignore CHANGED
@@ -41,3 +41,7 @@ spec/test_app/db
41
41
  # ignore IDE files
42
42
  .idea
43
43
  .vscode
44
+
45
+ # ignore Gemfile.locks https://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
46
+ /spec/test_app/Gemfile.lock
47
+ /Gemfile.lock
data/Gemfile CHANGED
@@ -4,5 +4,10 @@ gem 'hyper-spec', path: '../hyper-spec'
4
4
  gem 'hyperstack-config', path: '../hyperstack-config'
5
5
  gem 'hyper-store', path: '../hyper-store'
6
6
  gem 'hyper-state', path: '../hyper-state'
7
+ unless ENV['OPAL_VERSION']&.match("0.11")
8
+ gem 'opal-browser', git: 'https://github.com/opal/opal-browser'
9
+ end
10
+ gem 'hyper-trace', path: '../hyper-trace'
11
+
7
12
  #gem 'puma', '~> 3.11.0' # As of adding, version 3.12.0 isn't working so we are locking
8
13
  gemspec
@@ -8,45 +8,37 @@ Gem::Specification.new do |spec|
8
8
 
9
9
  spec.authors = ['David Chang', 'Adam Jahn', 'Mitch VanDuyn', 'Jan Biedermann', 'Adam Creekroad']
10
10
  spec.email = ['mitch@catprint.com']
11
- spec.homepage = 'http://ruby-hyperloop.org'
11
+ spec.homepage = 'http://hyperstack.org'
12
12
  spec.summary = 'Opal Ruby wrapper of React.js library.'
13
13
  spec.license = 'MIT'
14
14
  spec.description = 'Write React UI components in pure Ruby.'
15
- # spec.metadata = {
16
- # "homepage_uri" => 'http://ruby-hyperloop.org',
17
- # "source_code_uri" => 'https://github.com/ruby-hyperloop/hyper-component'
18
- # }
19
-
20
15
  spec.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(gemfiles|spec)/}) }
21
16
  spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
17
  spec.require_paths = ['lib']
23
18
 
24
19
  spec.add_dependency 'hyper-state', Hyperstack::Component::VERSION
25
20
  spec.add_dependency 'hyperstack-config', Hyperstack::Component::VERSION
26
- spec.add_dependency 'libv8', '~> 6.3.0' # see https://github.com/discourse/mini_racer/issues/92
27
- spec.add_dependency 'mini_racer', '~> 0.1.15'
28
- spec.add_dependency 'opal', '>= 0.11.0', '< 0.12.0'
29
21
  spec.add_dependency 'opal-activesupport', '~> 0.3.1'
30
22
  spec.add_dependency 'react-rails', '>= 2.4.0', '< 2.5.0'
31
23
 
32
- spec.add_development_dependency 'bundler', '~> 1.16.0'
24
+ spec.add_development_dependency 'bundler'
33
25
  spec.add_development_dependency 'chromedriver-helper'
34
26
  spec.add_development_dependency 'hyper-spec', Hyperstack::Component::VERSION
35
27
  spec.add_development_dependency 'jquery-rails'
36
28
  spec.add_development_dependency 'listen'
37
29
  spec.add_development_dependency 'mime-types'
30
+ spec.add_development_dependency 'mini_racer'
38
31
  spec.add_development_dependency 'nokogiri'
39
32
  spec.add_development_dependency 'opal-jquery'
40
- spec.add_development_dependency 'opal-rails', '~> 0.9.4'
41
- spec.add_development_dependency 'opal-rspec'
42
- spec.add_development_dependency 'pry'
33
+ spec.add_development_dependency 'opal-rails', '>= 0.9.4', '< 2.0'
43
34
  spec.add_development_dependency 'pry-rescue'
35
+ spec.add_development_dependency 'pry-stack_explorer'
44
36
  spec.add_development_dependency 'puma'
45
- spec.add_development_dependency 'rails', '>= 4.0.0'
37
+ spec.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '>= 5.0.0', '< 7.0'
46
38
  spec.add_development_dependency 'rails-controller-testing'
47
39
  spec.add_development_dependency 'rake'
48
40
  spec.add_development_dependency 'rspec-rails'
49
- spec.add_development_dependency 'rubocop', '~> 0.51.0'
50
- spec.add_development_dependency 'sqlite3'
41
+ spec.add_development_dependency 'rubocop' #, '~> 0.51.0'
42
+ spec.add_development_dependency 'sqlite3', '~> 1.4.2'
51
43
  spec.add_development_dependency 'timecop', '~> 0.8.1'
52
44
  end
@@ -1,9 +1,9 @@
1
1
  require 'hyperstack/internal/component'
2
2
 
3
- Hyperstack.import 'hyper-state'
4
3
  Hyperstack.js_import 'react/react-source-browser', client_only: true, defines: %w[ReactDOM React]
5
4
  Hyperstack.js_import 'react/react-source-server', server_only: true, defines: 'React'
6
5
  Hyperstack.import 'browser/delay', client_only: true
6
+ Hyperstack.import 'browser/interval', client_only: true
7
7
  Hyperstack.js_import 'react_ujs', defines: 'ReactRailsUJS'
8
8
  Hyperstack.import 'hyper-component' # TODO: confirm this does not break anything. Added while converting hyperloop->hyperstack
9
9
  Hyperstack.import 'hyperstack/component/auto-import' # TODO: confirm we can cancel the import
@@ -12,6 +12,7 @@ if RUBY_ENGINE == 'opal'
12
12
  require 'hyperstack/internal/callbacks'
13
13
  require 'hyperstack/internal/auto_unmount'
14
14
  require 'native'
15
+ require 'json'
15
16
  require 'hyperstack/state/observer'
16
17
  require 'hyperstack/internal/component/validator'
17
18
  require 'hyperstack/component/element'
@@ -22,14 +23,24 @@ if RUBY_ENGINE == 'opal'
22
23
  require 'hyperstack/component/event'
23
24
  require 'hyperstack/internal/component/rendering_context'
24
25
  require 'hyperstack/ext/component/object'
26
+ require 'hyperstack/ext/component/kernel'
25
27
  require 'hyperstack/ext/component/number'
26
28
  require 'hyperstack/ext/component/boolean'
29
+ require 'hyperstack/ext/component/array'
30
+ require 'hyperstack/ext/component/enumerable'
31
+ require 'hyperstack/ext/component/time'
27
32
  require 'hyperstack/component/isomorphic_helpers'
28
33
  require 'hyperstack/component/react_api'
29
34
  require 'hyperstack/internal/component/top_level_rails_component'
35
+ require 'hyperstack/component/while_loading'
36
+ require 'hyperstack/component/free_render'
37
+ require 'hyperstack/internal/component/rescue_wrapper'
38
+ require 'hyperstack/internal/component/while_loading_wrapper'
39
+
30
40
  require 'hyperstack/component/version'
31
41
  else
32
42
  require 'opal'
43
+ require 'hyper-state'
33
44
  require 'opal-activesupport'
34
45
  require 'hyperstack/component/version'
35
46
  require 'hyperstack/internal/component/rails'
@@ -1,7 +1,6 @@
1
1
  require 'hyperstack/ext/component/string'
2
2
  require 'hyperstack/ext/component/hash'
3
3
  require 'active_support/core_ext/class/attribute'
4
- require 'hyperstack/internal/auto_unmount'
5
4
  require 'hyperstack/internal/component/rendering_context'
6
5
  require 'hyperstack/internal/component'
7
6
  require 'hyperstack/internal/component/instance_methods'
@@ -19,13 +18,40 @@ module Hyperstack
19
18
  base.include(Hyperstack::Internal::Component::ShouldComponentUpdate)
20
19
  base.class_eval do
21
20
  class_attribute :initial_state
22
- define_callback :before_mount
21
+
22
+ method_args_deprecation_check = lambda do |name, sself, proc, *args|
23
+ if proc.arity.zero?
24
+ args = []
25
+ else
26
+ deprecation_warning "In the future #{name} callbacks will not receive any parameters."
27
+ end
28
+ sself.instance_exec(*args, &proc)
29
+ args
30
+ end
31
+
32
+ define_callback :before_mount, before_call_hook: method_args_deprecation_check
23
33
  define_callback :after_mount
24
- define_callback :before_receive_props
25
- define_callback :before_update
34
+ define_callback(
35
+ :before_new_params,
36
+ after_define_hook: lambda do |klass|
37
+ klass.deprecation_warning "`before_new_params` has been deprecated. The base "\
38
+ "method componentWillReceiveProps is deprecated in React without replacement"
39
+ end
40
+ )
41
+ define_callback(:before_update, before_call_hook: method_args_deprecation_check)
26
42
  define_callback :after_update
27
- #define_callback :before_unmount defined already by Async module
28
- define_callback(:after_error) { Hyperstack::Internal::Component::ReactWrapper.add_after_error_hook(base) }
43
+ define_callback(
44
+ :__hyperstack_component_after_render_hook,
45
+ before_call_hook: ->(_, sself, proc, *args) { [*sself.instance_exec(*args, &proc)] }
46
+ )
47
+ define_callback(
48
+ :__hyperstack_component_rescue_hook,
49
+ before_call_hook: ->(_, sself, proc, *args) { sself.instance_exec(*args, &proc) }
50
+ )
51
+ define_callback(
52
+ :after_error,
53
+ after_define_hook: ->(klass) { Hyperstack::Internal::Component::ReactWrapper.add_after_error_hook(klass) }
54
+ )
29
55
  end
30
56
  base.extend(Hyperstack::Internal::Component::ClassMethods)
31
57
  unless `Opal.__hyperstack_component_original_defn`
@@ -93,13 +119,14 @@ module Hyperstack
93
119
  def component_did_mount
94
120
  observing(update_objects: true) do
95
121
  run_callback(:after_mount)
122
+ Hyperstack::Internal::Component::RenderingContext.quiet_test(self)
96
123
  end
97
124
  end
98
125
 
99
126
  def component_will_receive_props(next_props)
100
127
  # need to rethink how this works in opal-react, or if its actually that useful within the react.rb environment
101
128
  # for now we are just using it to clear processed_params
102
- observing(immediate_update: true) { run_callback(:before_receive_props, next_props) }
129
+ observing(immediate_update: true) { run_callback(:before_new_params, next_props) }
103
130
  @__hyperstack_component_receiving_props = true
104
131
  end
105
132
 
@@ -112,7 +139,10 @@ module Hyperstack
112
139
  end
113
140
 
114
141
  def component_did_update(prev_props, prev_state)
115
- observing(update_objects: true) { run_callback(:after_update, prev_props, prev_state) }
142
+ observing(update_objects: true) do
143
+ run_callback(:after_update, prev_props, prev_state)
144
+ Hyperstack::Internal::Component::RenderingContext.quiet_test(self)
145
+ end
116
146
  end
117
147
 
118
148
  def component_will_unmount
@@ -124,7 +154,9 @@ module Hyperstack
124
154
  end
125
155
 
126
156
  def component_did_catch(error, info)
127
- observing { run_callback(:after_error, error, info) }
157
+ observing do
158
+ run_callback(:after_error, error, info)
159
+ end
128
160
  end
129
161
 
130
162
  def mutations(_objects)
@@ -156,9 +188,27 @@ module Hyperstack
156
188
  @__hyperstack_component_waiting_on_resources
157
189
  end
158
190
 
191
+ def __hyperstack_component_run_post_render_hooks(element)
192
+ run_callback(:__hyperstack_component_after_render_hook, element).first
193
+ end
194
+
195
+ def _run_before_render_callbacks
196
+ # eventually add before_update if @__component_mounted
197
+ # but that will not perfectly match the current React behavior.
198
+ # However that behavior is deprecated, and so once we have
199
+ # given a chance for the code to be updated we can switch this over
200
+ # and switch the deprecation notice to an error.
201
+ component_will_mount unless @__component_mounted
202
+ @__component_mounted = true
203
+ end
204
+
205
+
159
206
  def _render_wrapper
207
+ _run_before_render_callbacks
160
208
  observing(rendering: true) do
161
- element = Hyperstack::Internal::Component::RenderingContext.render(nil) { render || '' }
209
+ element = Hyperstack::Internal::Component::RenderingContext.render(nil) do
210
+ render || ""
211
+ end
162
212
  @__hyperstack_component_waiting_on_resources =
163
213
  element.waiting_on_resources if element.respond_to? :waiting_on_resources
164
214
  element
@@ -22,7 +22,7 @@ module Hyperstack
22
22
  %x{
23
23
  React.Children.forEach(#{@children}, function(context){
24
24
  #{
25
- element = Element.new(`context`)
25
+ element = Element.new(`context`, :wrap_child)
26
26
  block.call(element)
27
27
  collection << element
28
28
  }
@@ -15,29 +15,89 @@ module Hyperstack
15
15
  # by using method missing
16
16
  #
17
17
  class Element
18
- include Native
19
18
 
20
- alias_native :element_type, :type
21
- alias_native :props, :props
19
+ # $$typeof: Symbol(react.element)
20
+ # key: null
21
+ # props: {}
22
+ # ref: null
23
+ # type: "div"
24
+ # _ _owner: null
22
25
 
23
- attr_reader :type
26
+ attr_reader :type
27
+
28
+ attr_reader :element_type # change this so name does not conflict - change to element type
24
29
  attr_reader :properties
25
30
  attr_reader :block
31
+ attr_reader :to_n
26
32
 
27
33
  attr_accessor :waiting_on_resources
28
34
 
29
- def initialize(native_element, type = nil, properties = {}, block = nil)
30
- @type = type
35
+ def set_native_attributes(native_element)
36
+ @key = `native_element.key`
37
+ @props = `native_element.props`
38
+ @ref = `native_element.ref`
39
+ @type = `native_element.type`
40
+ @_owner = `native_element._owner`
41
+ @_props_as_hash = Hash.new(@props)
42
+ end
43
+
44
+ def props
45
+ @_props_as_hash
46
+ end
47
+
48
+ def convert_string(native_element, element_type, props, block)
49
+ return native_element unless `native_element['$is_a?']`
50
+ return native_element unless native_element.is_a? String
51
+ raise "Internal Error Element.new called with string, but non-nil props or block" if !props.empty? || block
52
+
53
+ if element_type == :wrap_child
54
+ `React.createElement(React.Fragment, null, [native_element])`
55
+ else
56
+ `React.createElement(native_element, null)`
57
+ end
58
+ end
59
+
60
+ def initialize(native_element, element_type = nil, properties = {}, block = nil)
61
+
62
+ native_element = convert_string(native_element, element_type, properties, block)
63
+ @element_type = element_type unless element_type == :wrap_child
31
64
  @properties = (`typeof #{properties} === 'undefined'` ? nil : properties) || {}
32
65
  @block = block
33
- @native = native_element
66
+ `#{self}.$$typeof = native_element.$$typeof`
67
+ @to_n = self
68
+ set_native_attributes(native_element)
69
+ rescue Exception
34
70
  end
35
71
 
36
- # Attach event handlers.
72
+ def children
73
+ `#{@props}.children`
74
+ end
75
+
76
+ def _update_ref(x)
77
+ @_ref = x
78
+ @_child_element._update_ref(x) if @_child_element
79
+ end
80
+
81
+ def ref # this will not conflict with React's on ref attribute okay because its $ref!!!
82
+ return @_ref if @_ref
83
+ raise("The instance of #{self.element_type} has not been mounted yet") if properties[:ref]
84
+ raise("Attempt to get a ref on #{self.element_type} which is a static component.")
85
+ end
86
+
87
+ def dom_node
88
+ `typeof #{ref}.$dom_node == 'function'` ? ref.dom_node : ref
89
+ end
90
+
91
+ # Attach event handlers. skip false, nil and blank event names
37
92
 
38
93
  def on(*event_names, &block)
39
- event_names.each { |event_name| merge_event_prop!(event_name, &block) }
40
- @native = `React.cloneElement(#{@native}, #{@properties.shallow_to_n})`
94
+ any_found = false
95
+ event_names.each do |event_name|
96
+ next unless event_name && event_name.strip != ''
97
+ merge_event_prop!(event_name, &block)
98
+ any_found = true
99
+ end
100
+ set_native_attributes(`React.cloneElement(#{self}, #{@properties.shallow_to_n})`) if any_found
41
101
  self
42
102
  end
43
103
 
@@ -45,14 +105,14 @@ module Hyperstack
45
105
  # Used for elements that are not yet in DOM, i.e. they are provided as children
46
106
  # or they have been explicitly removed from the rendering context using the delete method.
47
107
 
48
- def render(props = {}, &new_block)
108
+ def render(*props)
49
109
  if props.empty?
50
110
  Hyperstack::Internal::Component::RenderingContext.render(self)
51
111
  else
52
- props = Hyperstack::Internal::Component::ReactWrapper.convert_props(props)
53
- Hyperstack::Internal::Component::RenderingContext.render(
54
- Element.new(`React.cloneElement(#{@native}, #{props.shallow_to_n})`,
55
- type, @properties.merge(props), block)
112
+ props = Hyperstack::Internal::Component::ReactWrapper.convert_props(element_type, @properties, *props)
113
+ @_child_element = Hyperstack::Internal::Component::RenderingContext.render(
114
+ Element.new(`React.cloneElement(#{self}, #{props.shallow_to_n})`,
115
+ element_type, props, block)
56
116
  )
57
117
  end
58
118
  end
@@ -60,11 +120,12 @@ module Hyperstack
60
120
  # Delete (remove) element from rendering context, the element may later be added back in
61
121
  # using the render method.
62
122
 
63
- def delete
123
+ def ~
64
124
  Hyperstack::Internal::Component::RenderingContext.delete(self)
65
125
  end
66
126
  # Deprecated version of delete method
67
- alias as_node delete
127
+ alias as_node ~
128
+ alias delete ~
68
129
 
69
130
  private
70
131
 
@@ -89,26 +150,37 @@ module Hyperstack
89
150
  merge_built_in_event_prop! name, &block
90
151
  elsif event_name == :enter
91
152
  merge_built_in_event_prop!('onKeyDown') { |evt| yield(evt) if evt.key_code == 13 }
92
- elsif @type.instance_variable_get('@native_import')
153
+ elsif element_type.instance_variable_get('@native_import')
93
154
  merge_component_event_prop! name, &block
94
155
  else
95
156
  merge_component_event_prop! "on_#{event_name}", &block
96
157
  end
97
158
  end
98
159
 
99
- def merge_built_in_event_prop!(prop_name)
160
+ def merge_built_in_event_prop!(prop_name, &block)
100
161
  @properties.merge!(
101
162
  prop_name => %x{
102
163
  function(){
103
164
  var react_event = arguments[0];
165
+ if (arguments.length == 0 || !react_event.nativeEvent) {
166
+ return #{yield(*Array(`arguments`))}
167
+ }
104
168
  var all_args;
105
169
  var other_args;
106
170
  if (arguments.length > 1) {
107
171
  all_args = Array.prototype.slice.call(arguments);
108
172
  other_args = all_args.slice(1, arguments.length);
109
- return #{yield(Event.new(`react_event`), *(`other_args`))};
173
+ return #{
174
+ Internal::State::Mapper.ignore_bulk_updates(
175
+ Event.new(`react_event`), *(`other_args`), &block
176
+ )
177
+ };
110
178
  } else {
111
- return #{yield(Event.new(`react_event`))};
179
+ return #{
180
+ Internal::State::Mapper.ignore_bulk_updates(
181
+ Event.new(`react_event`), &block
182
+ )
183
+ };
112
184
  }
113
185
  }
114
186
  }
@@ -1,7 +1,7 @@
1
1
  module Hyperstack
2
2
  module Component
3
3
  class Event
4
- include Native
4
+ include Native::Wrapper
5
5
  alias_native :bubbles, :bubbles
6
6
  alias_native :cancelable, :cancelable
7
7
  alias_native :current_target, :currentTarget