hyper-component 1.0.alpha1.5 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5eb3f7c53a31ed9f6708f9fd1251f3ed52f7d54e5894145abaaf4ac4e5ac7fce
4
- data.tar.gz: b95ea7df69882114a1a55f772911ba2b609221bde04df9e629e1278c0e71ea73
3
+ metadata.gz: 280f2800045d849e7cc7eb6e517673861a9a0dd15ea96a204bc246f7c35fdf96
4
+ data.tar.gz: 5f15dcac1988d4aa3443db720bb253e4b0f1cf36fa59884fafdf8d73ade1bbb5
5
5
  SHA512:
6
- metadata.gz: b7022103f15e46d7251addacac7ca755bb2cc2e7d52ae9ec8ebcd9fbb24ada6db90e77d3d689ad20a058a60e84192f00ea88f5d99065c2b86420187f2a0a2057
7
- data.tar.gz: 44d0acecd8dc27123a35d0db8fa32f9cbdbe6715c523661a618114ad157891dfec8ebc226b6eff70e3a2a562271e3144d477e16f9110a8a274058edd1fb188cf
6
+ metadata.gz: d56717e2ef07a3b4e94e3dbe933a1710167bf8a6a9318f2667e986d055d14af3f2a86daa426ef20bdd394352398dbdd6877615daf4b7a1454e7bea40d9014c04
7
+ data.tar.gz: 5d7920af6aa4843c8141c41b44ca7120d46be0be7a752336a7d48fb2cfc5aad76c985b2b5b3586391c4baed240b9c3d3655c59db3db07a6bdf0890c07e784614
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
@@ -23,30 +23,27 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'hyper-state', Hyperstack::Component::VERSION
25
25
  spec.add_dependency 'hyperstack-config', Hyperstack::Component::VERSION
26
- spec.add_dependency 'libv8', '~> 6.7.0'
27
- spec.add_dependency 'mini_racer', '~> 0.2.4'
28
- spec.add_dependency 'opal', '>= 0.11.0', '< 0.12.0'
29
26
  spec.add_dependency 'opal-activesupport', '~> 0.3.1'
30
27
  spec.add_dependency 'react-rails', '>= 2.4.0', '< 2.5.0'
31
28
 
32
- spec.add_development_dependency 'bundler', ['>= 1.17.3', '< 2.1']
29
+ spec.add_development_dependency 'bundler'
33
30
  spec.add_development_dependency 'chromedriver-helper'
34
31
  spec.add_development_dependency 'hyper-spec', Hyperstack::Component::VERSION
35
32
  spec.add_development_dependency 'jquery-rails'
36
33
  spec.add_development_dependency 'listen'
37
34
  spec.add_development_dependency 'mime-types'
35
+ spec.add_development_dependency 'mini_racer'
38
36
  spec.add_development_dependency 'nokogiri'
39
37
  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'
38
+ spec.add_development_dependency 'opal-rails', '>= 0.9.4', '< 2.0'
43
39
  spec.add_development_dependency 'pry-rescue'
40
+ spec.add_development_dependency 'pry-stack_explorer'
44
41
  spec.add_development_dependency 'puma'
45
- spec.add_development_dependency 'rails', '>= 4.0.0'
42
+ spec.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '>= 5.0.0', '< 7.0'
46
43
  spec.add_development_dependency 'rails-controller-testing'
47
44
  spec.add_development_dependency 'rake'
48
45
  spec.add_development_dependency 'rspec-rails'
49
46
  spec.add_development_dependency 'rubocop', '~> 0.51.0'
50
- spec.add_development_dependency 'sqlite3', '~> 1.3.6' # see https://github.com/rails/rails/issues/35153
47
+ spec.add_development_dependency 'sqlite3', '~> 1.4.2'
51
48
  spec.add_development_dependency 'timecop', '~> 0.8.1'
52
49
  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
@@ -38,6 +38,7 @@ if RUBY_ENGINE == 'opal'
38
38
  require 'hyperstack/component/version'
39
39
  else
40
40
  require 'opal'
41
+ require 'hyper-state'
41
42
  require 'opal-activesupport'
42
43
  require 'hyperstack/component/version'
43
44
  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,15 +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_new_params
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 :__hyperstack_component_after_render_hook
28
- define_callback :__hyperstack_component_rescue_hook
29
- #define_callback :before_unmount defined already by Async module
30
- 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
+ )
31
55
  end
32
56
  base.extend(Hyperstack::Internal::Component::ClassMethods)
33
57
  unless `Opal.__hyperstack_component_original_defn`
@@ -165,13 +189,25 @@ module Hyperstack
165
189
  end
166
190
 
167
191
  def __hyperstack_component_run_post_render_hooks(element)
168
- run_callback(:__hyperstack_component_after_render_hook, element) { |*args| args }.first
192
+ run_callback(:__hyperstack_component_after_render_hook, element).first
169
193
  end
170
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
+
171
206
  def _render_wrapper
207
+ _run_before_render_callbacks
172
208
  observing(rendering: true) do
173
209
  element = Hyperstack::Internal::Component::RenderingContext.render(nil) do
174
- render || ''
210
+ render || ""
175
211
  end
176
212
  @__hyperstack_component_waiting_on_resources =
177
213
  element.waiting_on_resources if element.respond_to? :waiting_on_resources
@@ -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,33 +15,73 @@ 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
70
+ end
71
+
72
+ def children
73
+ `#{@props}.children`
34
74
  end
35
75
 
36
76
  def _update_ref(x)
37
- @ref = x
77
+ @_ref = x
38
78
  @_child_element._update_ref(x) if @_child_element
39
79
  end
40
80
 
41
- def ref
42
- return @ref if @ref
43
- raise("The instance of #{self.type} has not been mounted yet") if properties[:ref]
44
- raise("Attempt to get a ref on #{self.type} which is a static component.")
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.")
45
85
  end
46
86
 
47
87
  def dom_node
@@ -57,7 +97,7 @@ module Hyperstack
57
97
  merge_event_prop!(event_name, &block)
58
98
  any_found = true
59
99
  end
60
- @native = `React.cloneElement(#{@native}, #{@properties.shallow_to_n})` if any_found
100
+ set_native_attributes(`React.cloneElement(#{self}, #{@properties.shallow_to_n})`) if any_found
61
101
  self
62
102
  end
63
103
 
@@ -69,10 +109,10 @@ module Hyperstack
69
109
  if props.empty?
70
110
  Hyperstack::Internal::Component::RenderingContext.render(self)
71
111
  else
72
- props = Hyperstack::Internal::Component::ReactWrapper.convert_props(@type, @properties, *props)
112
+ props = Hyperstack::Internal::Component::ReactWrapper.convert_props(element_type, @properties, *props)
73
113
  @_child_element = Hyperstack::Internal::Component::RenderingContext.render(
74
- Element.new(`React.cloneElement(#{@native}, #{props.shallow_to_n})`,
75
- type, props, block)
114
+ Element.new(`React.cloneElement(#{self}, #{props.shallow_to_n})`,
115
+ element_type, props, block)
76
116
  )
77
117
  end
78
118
  end
@@ -80,11 +120,12 @@ module Hyperstack
80
120
  # Delete (remove) element from rendering context, the element may later be added back in
81
121
  # using the render method.
82
122
 
83
- def delete
123
+ def ~
84
124
  Hyperstack::Internal::Component::RenderingContext.delete(self)
85
125
  end
86
126
  # Deprecated version of delete method
87
- alias as_node delete
127
+ alias as_node ~
128
+ alias delete ~
88
129
 
89
130
  private
90
131
 
@@ -109,7 +150,7 @@ module Hyperstack
109
150
  merge_built_in_event_prop! name, &block
110
151
  elsif event_name == :enter
111
152
  merge_built_in_event_prop!('onKeyDown') { |evt| yield(evt) if evt.key_code == 13 }
112
- elsif @type.instance_variable_get('@native_import')
153
+ elsif element_type.instance_variable_get('@native_import')
113
154
  merge_component_event_prop! name, &block
114
155
  else
115
156
  merge_component_event_prop! "on_#{event_name}", &block
@@ -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
@@ -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
- if on_opal_server?
22
- `console.history = []` rescue nil
23
- message = "************************ React Prerendering Context Initialized #{name} ***********************"
24
- else
25
- message = "************************ React Browser Context Initialized ****************************"
26
- end
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
- @context
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('"', "'")
@@ -1,5 +1,5 @@
1
1
  module Hyperstack
2
2
  module Component
3
- VERSION = '1.0.alpha1.5' # '1.0.alpha1.5'
3
+ VERSION = '1.0.alpha1.6' # '1.0.alpha1.5'
4
4
  end
5
5
  end
@@ -16,7 +16,7 @@ module Hyperstack
16
16
  if Hyperstack::Component::IsomorphicHelpers.on_opal_client?
17
17
  %x{
18
18
  function onError(event) {
19
- if (event.message.startsWith('Uncaught NotQuiet: ')) event.preventDefault();
19
+ if (event.message.match(/^Uncaught NotQuiet: /)) event.preventDefault();
20
20
  }
21
21
 
22
22
  window.addEventListener('error', onError);
@@ -50,7 +50,7 @@ module Hyperstack
50
50
  def render(container = nil, params = {}, &block)
51
51
  Tags.included(self)
52
52
  if container
53
- container = container.type if container.is_a? Hyperstack::Component::Element
53
+ container = container.element_type if container.is_a? Hyperstack::Component::Element
54
54
  define_method(:__hyperstack_component_render) do
55
55
  __hyperstack_component_select_wrappers do
56
56
  RenderingContext.render(container, params) do
@@ -28,7 +28,7 @@ module Hyperstack
28
28
  self,
29
29
  Hyperstack::Internal::Component::RenderingContext.build do
30
30
  Hyperstack::Internal::Component::RenderingContext.render(
31
- type, @properties, args, class: haml_class_name(class_name), &new_block
31
+ element_type, @properties, args, class: haml_class_name(class_name), &new_block
32
32
  )
33
33
  end
34
34
  )
@@ -43,6 +43,9 @@ module Hyperstack
43
43
  end
44
44
 
45
45
  def footers
46
+ return if @hyperstack_footers_rendered
47
+
48
+ @hyperstack_footers_rendered = true
46
49
  Hyperstack::Component::IsomorphicHelpers.prerender_footers(controller)
47
50
  end
48
51
  end
@@ -13,7 +13,11 @@ module Hyperstack
13
13
 
14
14
  class ContextualRenderer < React::ServerRendering::BundleRenderer
15
15
  def initialize(options = {})
16
- super(options)
16
+ unless v8_runtime?
17
+ raise "Hyperstack prerendering only works with MiniRacer. Add 'mini_racer' to your Gemfile"
18
+ end
19
+
20
+ super({ files: ['hyperstack-prerender-loader.js'] }.merge(options))
17
21
  ComponentLoader.new(v8_context).load
18
22
  end
19
23
 
@@ -9,7 +9,9 @@ module Hyperstack
9
9
  module ServerRendering
10
10
  class HyperTestAssetContainer
11
11
  def find_asset(logical_path)
12
- ::Rails.cache.read(logical_path)
12
+ # we skip the container if it raises an error so we
13
+ # don't care if we are running under hyperspec or not
14
+ HyperSpec::Internal::Controller.cache_read(logical_path)
13
15
  end
14
16
  end
15
17
 
@@ -24,7 +26,7 @@ module Hyperstack
24
26
  if React::ServerRendering::WebpackerManifestContainer.compatible?
25
27
  @ass_containers << React::ServerRendering::WebpackerManifestContainer.new
26
28
  end
27
- @ass_containers << HyperTestAssetContainer.new if ::Rails.env.test?
29
+ @ass_containers << HyperTestAssetContainer.new
28
30
  end
29
31
 
30
32
  def find_asset(logical_path)
@@ -19,7 +19,7 @@ module Hyperstack
19
19
  @@component_classes = {}
20
20
 
21
21
  def self.stateless?(ncc)
22
- `typeof #{ncc} === 'function' && !(#{ncc}.prototype && #{ncc}.prototype.isReactComponent)`
22
+ `typeof #{ncc} === 'symbol' || (typeof #{ncc} === 'function' && !(#{ncc}.prototype && #{ncc}.prototype.isReactComponent))`
23
23
  end
24
24
 
25
25
  def self.import_native_component(opal_class, native_class)
@@ -30,6 +30,7 @@ module Hyperstack
30
30
  def self.eval_native_react_component(name)
31
31
  component = `eval(name)`
32
32
  raise "#{name} is not defined" if `#{component} === undefined`
33
+
33
34
  component = `component.default` if `component.__esModule`
34
35
  is_component_class = `#{component}.prototype !== undefined` &&
35
36
  (`!!#{component}.prototype.isReactComponent` ||
@@ -43,9 +44,11 @@ module Hyperstack
43
44
 
44
45
  def self.native_react_component?(name = nil)
45
46
  return false unless name
47
+
46
48
  eval_native_react_component(name)
47
49
  true
48
- rescue
50
+ # Exception to be compatible with all versions of opal
51
+ rescue Exception # rubocop:disable Lint/RescueException
49
52
  false
50
53
  end
51
54
 
@@ -64,93 +67,81 @@ module Hyperstack
64
67
  end
65
68
 
66
69
  def self.create_native_react_class(type)
70
+ raise "createReactClass is undefined. Add the 'react-create-class' npm module, and import it as 'createReactClass'" if `typeof(createReactClass)=='undefined'`
67
71
  raise "Provided class should define `render` method" if !(type.method_defined? :render)
68
- render_fn = (type.method_defined? :_render_wrapper) ? :_render_wrapper : :render
72
+ old_school = !type.method_defined?(:_render_wrapper)
73
+ render_fn = old_school ? :render : :_render_wrapper
69
74
  # this was hashing type.to_s, not sure why but .to_s does not work as it Foo::Bar::View.to_s just returns "View"
70
-
71
75
  @@component_classes[type] ||= begin
72
76
  comp = %x{
73
- class extends React.Component {
74
- constructor(props) {
75
- super(props);
77
+ createReactClass({
78
+ getInitialState: function() {
76
79
  this.mixins = #{type.respond_to?(:native_mixins) ? type.native_mixins : `[]`};
77
80
  this.statics = #{type.respond_to?(:static_call_backs) ? type.static_call_backs.to_n : `{}`};
78
- this.state = {};
79
81
  this.__opalInstanceInitializedState = false;
80
82
  this.__opalInstanceSyncSetState = true;
81
83
  this.__opalInstance = #{type.new(`this`)};
82
84
  this.__opalInstanceInitializedState = true;
83
85
  this.__opalInstanceSyncSetState = false;
84
86
  this.__name = #{type.name};
85
- }
86
- static get displayName() {
87
- if (typeof this.__name != "undefined") {
88
- return this.__name;
89
- } else {
90
- return #{type.name};
91
- }
92
- }
93
- static set displayName(name) {
94
- this.__name = name;
95
- }
96
- static get defaultProps() {
87
+ return {}
88
+ },
89
+ displayName: #{type.name},
90
+ getDefaultProps: function() {
97
91
  return #{type.respond_to?(:default_props) ? type.default_props.to_n : `{}`};
98
- }
99
- static get propTypes() {
100
- return #{type.respond_to?(:prop_types) ? type.prop_types.to_n : `{}`};
101
- }
102
- componentWillMount() {
92
+ },
93
+ propTypes: #{type.respond_to?(:prop_types) ? type.prop_types.to_n : `{}`},
94
+ componentWillMount: old_school && function() {
103
95
  if (#{type.method_defined? :component_will_mount}) {
104
96
  this.__opalInstanceSyncSetState = true;
105
97
  this.__opalInstance.$component_will_mount();
106
98
  this.__opalInstanceSyncSetState = false;
107
99
  }
108
- }
109
- componentDidMount() {
100
+ },
101
+ componentDidMount: function() {
110
102
  this.__opalInstance.__hyperstack_component_is_mounted = true
111
103
  if (#{type.method_defined? :component_did_mount}) {
112
104
  this.__opalInstanceSyncSetState = false;
113
105
  this.__opalInstance.$component_did_mount();
114
106
  }
115
- }
116
- componentWillReceiveProps(next_props) {
107
+ },
108
+ UNSAFE_componentWillReceiveProps: function(next_props) {
117
109
  if (#{type.method_defined? :component_will_receive_props}) {
118
110
  this.__opalInstanceSyncSetState = true;
119
111
  this.__opalInstance.$component_will_receive_props(Opal.Hash.$new(next_props));
120
112
  this.__opalInstanceSyncSetState = false;
121
113
  }
122
- }
123
- shouldComponentUpdate(next_props, next_state) {
114
+ },
115
+ shouldComponentUpdate: function(next_props, next_state) {
124
116
  if (#{type.method_defined? :should_component_update?}) {
125
117
  this.__opalInstanceSyncSetState = false;
126
118
  return this.__opalInstance["$should_component_update?"](Opal.Hash.$new(next_props), Opal.Hash.$new(next_state));
127
119
  } else { return true; }
128
- }
129
- componentWillUpdate(next_props, next_state) {
120
+ },
121
+ UNSAFE_componentWillUpdate: function(next_props, next_state) {
130
122
  if (#{type.method_defined? :component_will_update}) {
131
123
  this.__opalInstanceSyncSetState = false;
132
124
  this.__opalInstance.$component_will_update(Opal.Hash.$new(next_props), Opal.Hash.$new(next_state));
133
125
  }
134
- }
135
- componentDidUpdate(prev_props, prev_state) {
126
+ },
127
+ componentDidUpdate: function(prev_props, prev_state) {
136
128
  if (#{type.method_defined? :component_did_update}) {
137
129
  this.__opalInstanceSyncSetState = false;
138
130
  this.__opalInstance.$component_did_update(Opal.Hash.$new(prev_props), Opal.Hash.$new(prev_state));
139
131
  }
140
- }
141
- componentWillUnmount() {
132
+ },
133
+ componentWillUnmount: function() {
142
134
  if (#{type.method_defined? :component_will_unmount}) {
143
135
  this.__opalInstanceSyncSetState = false;
144
136
  this.__opalInstance.$component_will_unmount();
145
137
  }
146
138
  this.__opalInstance.__hyperstack_component_is_mounted = false;
147
- }
148
-
149
- render() {
139
+ },
140
+ render: function() {
150
141
  this.__opalInstanceSyncSetState = false;
151
142
  return this.__opalInstance.$send(render_fn).$to_n();
152
143
  }
153
- }
144
+ })
154
145
  }
155
146
  # check to see if there is an after_error callback. If there is add a
156
147
  # componentDidCatch handler. Because legacy behavior is to allow any object
@@ -19,27 +19,41 @@ module Hyperstack
19
19
  raise NotQuiet.new("#{component} is waiting on resources")
20
20
  end
21
21
 
22
+ def render_string(string)
23
+ @buffer ||= []
24
+ @buffer << string
25
+ end
26
+
22
27
  def render(name, *args, &block)
23
28
  was_outer_most = !@not_outer_most
24
29
  @not_outer_most = true
25
30
  remove_nodes_from_args(args)
26
- @buffer ||= [] unless @buffer
31
+ @buffer ||= [] #unless @buffer
27
32
  if block
28
33
  element = build do
29
34
  saved_waiting_on_resources = nil #waiting_on_resources what was the purpose of this its used below to or in with the current elements waiting_for_resources
30
35
  self.waiting_on_resources = nil
31
- run_child_block(name.nil?, &block)
36
+ run_child_block(&block)
32
37
  if name
33
38
  buffer = @buffer.dup
34
39
  ReactWrapper.create_element(name, *args) { buffer }.tap do |element|
35
40
  element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to?(:waiting_on_resources) }
36
41
  element.waiting_on_resources ||= waiting_on_resources if buffer.last.is_a?(String)
37
42
  end
38
- elsif @buffer.last.is_a? Hyperstack::Component::Element
39
- @buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
40
43
  else
41
- buffer_s = @buffer.last.to_s
42
- RenderingContext.render(:span) { buffer_s }.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
44
+ buffer = @buffer.collect do |item|
45
+ if item.is_a? Hyperstack::Component::Element
46
+ item.waiting_on_resources ||= saved_waiting_on_resources
47
+ item
48
+ else
49
+ RenderingContext.render(:span) { item.to_s }.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
50
+ end
51
+ end
52
+ if buffer.length > 1
53
+ buffer
54
+ else
55
+ buffer.first
56
+ end
43
57
  end
44
58
  end
45
59
  elsif name.is_a? Hyperstack::Component::Element
@@ -65,6 +79,7 @@ module Hyperstack
65
79
 
66
80
  def delete(element)
67
81
  @buffer.delete(element)
82
+ @last_deleted = element
68
83
  element
69
84
  end
70
85
  alias as_node delete
@@ -86,55 +101,74 @@ module Hyperstack
86
101
  end if args[0] && args[0].is_a?(Hash)
87
102
  end
88
103
 
89
- # run_child_block gathers the element(s) generated by a child block.
104
+ # run_child_block yields to the child rendering block which will put any
105
+ # elements to be rendered into the current rendering buffer.
106
+ #
90
107
  # for example when rendering this div: div { "hello".span; "goodby".span }
91
108
  # two child Elements will be generated.
92
109
  #
93
- # the final value of the block should either be
94
- # 1 an object that responds to :acts_as_string?
95
- # 2 a string,
96
- # 3 an element that is NOT yet pushed on the rendering buffer
97
- # 4 or the last element pushed on the buffer
110
+ # However the block itself will return a value, which in some cases should
111
+ # also added to the buffer:
112
+ #
113
+ # If the final value of the block is a
98
114
  #
99
- # in case 1 we render a span
100
- # in case 2 we automatically push the string onto the buffer
101
- # in case 3 we also push the Element onto the buffer IF the buffer is empty
102
- # case 4 requires no special processing
115
+ # a hyper model dummy value that is being loaded, then wrap it in a span and add it to the buffer
116
+ # a string (or if the buffer is empty any value), then add it to the buffer
117
+ # an Element, then add it on the buffer unless it has been just deleted
118
+ # #
119
+ # Note that the reason we don't always allow Strings to be automatically pushed is
120
+ # to avoid confusing results in situations like this:
121
+ # DIV { collection.each { |item| SPAN { item } } }
122
+ # If we accepted any object to be rendered this would generate:
123
+ # DIV { SPAN { collection[0] } SPAN { collection[n] } collection.to_s }
124
+ # which is probably not the desired output. If it was you would just append to_s
125
+ # to the end of the expression, to force it to be added to the output buffer.
103
126
  #
104
- # Once we have taken care of these special cases we do a check IF we are in an
105
- # outer rendering scope. In this case react only allows us to generate 1 Element
106
- # so we insure that is the case, and also check to make sure that element in the buffer
107
- # is the element returned
127
+ # However if the buffer is empty then it makes sense to automatically apply the `.to_s`
128
+ # to the value, and push it on the buffer, unless it is a falsy value or an array
108
129
 
109
- def run_child_block(is_outer_scope)
130
+ def run_child_block
110
131
  result = yield
111
- if result.respond_to?(:acts_as_string?) && result.acts_as_string?
112
- # hyper-mesh DummyValues respond to acts_as_string, and must
132
+ check_for_component_return(result)
133
+ if dummy_value?(result)
134
+ # hyper-mesh DummyValues must
113
135
  # be converted to spans INSIDE the parent, otherwise the waiting_on_resources
114
136
  # flag will get set in the wrong context
115
137
  RenderingContext.render(:span) { result.to_s }
116
- elsif result.is_a?(String) || (result.is_a?(Hyperstack::Component::Element) && @buffer.empty?)
117
- @buffer << result
138
+ elsif result.is_a?(Hyperstack::Component::Element)
139
+ @buffer << result if @buffer.empty? unless @last_deleted == result
140
+ elsif pushable_string?(result)
141
+ @buffer << result.to_s
118
142
  end
119
- raise_render_error(result) if is_outer_scope && @buffer != [result]
143
+ @last_deleted = nil
120
144
  end
121
145
 
122
- # heurestically raise a meaningful error based on the situation
123
-
124
- def raise_render_error(result)
125
- improper_render 'A different element was returned than was generated within the DSL.',
126
- 'Possibly improper use of Element#delete.' if @buffer.count == 1
127
- improper_render "Instead #{@buffer.count} elements were generated.",
128
- 'Do you want to wrap your elements in a div?' if @buffer.count > 1
129
- improper_render "Instead the component #{result} was returned.",
130
- "Did you mean #{result}()?" if result.try :hyper_component?
131
- improper_render "Instead the #{result.class} #{result} was returned.",
132
- 'You may need to convert this to a string.'
146
+ def check_for_component_return(result)
147
+ # check for a common error of saying (for example) DIV (without parens)
148
+ # which returns the DIV component class instead of a rendered DIV
149
+ return unless result.try :hyper_component?
150
+
151
+ Hyperstack::Component::IsomorphicHelpers.log(
152
+ "a component's render method returned the component class #{result}, did you mean to say #{result}()",
153
+ :warning
154
+ )
155
+ end
156
+
157
+ def dummy_value?(result)
158
+ result.respond_to?(:loading?) && result.loading?
159
+ end
160
+
161
+ def pushable_string?(result)
162
+ # if the buffer is not empty we will only push on strings, and ignore anything else
163
+ return result.is_a?(String) unless @buffer.empty?
164
+
165
+ # if the buffer IS empty then we can push on anything except we avoid nil, false and arrays
166
+ # as these are almost never what you want to render, and if you do there are mechanisms
167
+ # to render them explicitly
168
+ result && result.respond_to?(:to_n) && !result.is_a?(Array)
133
169
  end
134
170
 
135
171
  def improper_render(message, solution)
136
- raise "a component's render method must generate and return exactly 1 element or a string.\n"\
137
- " #{message} #{solution}"
138
172
  end
139
173
  end
140
174
  end
@@ -143,7 +177,7 @@ module Hyperstack
143
177
  end
144
178
 
145
179
  class Object
146
- [:span, :td, :th].each do |tag|
180
+ %i[span td th].each do |tag|
147
181
  define_method(tag) do |*args, &block|
148
182
  args.unshift(tag)
149
183
  # legacy hyperloop allowed tags to be lower case as well so if self is a component
@@ -155,24 +189,26 @@ class Object
155
189
  # in the component.
156
190
  # If we fully deprecate lowercase tags, then this next line can go...
157
191
  return send(*args, &block) if respond_to?(:hyper_component?) && hyper_component?
192
+
158
193
  Hyperstack::Internal::Component::RenderingContext.render(*args) { to_s }
159
194
  end
160
195
  end
161
196
 
162
-
163
197
  def para(*args, &block)
164
198
  args.unshift(:p)
165
199
  # see above comment
166
200
  return send(*args, &block) if respond_to?(:hyper_component?) && hyper_component?
201
+
167
202
  Hyperstack::Internal::Component::RenderingContext.render(*args) { to_s }
168
203
  end
169
204
 
170
205
  def br
171
206
  # see above comment
172
207
  return send(:br) if respond_to?(:hyper_component?) && hyper_component?
173
- Hyperstack::Internal::Component::RenderingContext.render(:span) do
174
- Hyperstack::Internal::Component::RenderingContext.render(to_s)
175
- Hyperstack::Internal::Component::RenderingContext.render(:br)
208
+
209
+ Hyperstack::Internal::Component::RenderingContext.render(Hyperstack::Internal::Component::Tags::FRAGMENT) do
210
+ Hyperstack::Internal::Component::RenderingContext.render(Hyperstack::Internal::Component::Tags::FRAGMENT) { to_s }
211
+ Hyperstack::Internal::Component::RenderingContext.render(Hyperstack::Internal::Component::Tags::BR)
176
212
  end
177
213
  end
178
214
 
@@ -27,7 +27,7 @@ module Hyperstack
27
27
 
28
28
  after_error do |error, info|
29
29
  args = RescueWrapper.after_error_args || [error, info]
30
- found, * = @Child.run_callback(:__hyperstack_component_rescue_hook, found, *args) { |a| a }
30
+ found, * = @Child.run_callback(:__hyperstack_component_rescue_hook, found, *args)
31
31
  unless found
32
32
  RescueWrapper.after_error_args = args
33
33
  raise error
@@ -32,6 +32,14 @@ module Hyperstack
32
32
  const_set tag.upcase, tag
33
33
  end
34
34
 
35
+ const_set "FRAGMENT", (
36
+ Class.new do
37
+ include Hyperstack::Component
38
+ render {}
39
+ Hyperstack::Internal::Component::ReactWrapper.import_native_component(self, `React.Fragment`)
40
+ end
41
+ )
42
+
35
43
  # this is used for haml style (i.e. DIV.foo.bar) class tags which is deprecated
36
44
  def self.html_tag_class_for(tag)
37
45
  downcased_tag = tag.downcase
@@ -85,6 +93,7 @@ module Hyperstack
85
93
 
86
94
  def lookup_const(name)
87
95
  return nil unless name =~ /^[A-Z]/
96
+ return Hyperstack::Internal::Component::Tags::FRAGMENT if name == "FRAGMENT"
88
97
  scopes = self.class.name.to_s.split('::').inject([Object]) do |nesting, next_const|
89
98
  nesting + [nesting.last.const_get(next_const)]
90
99
  end.reverse
@@ -11,7 +11,7 @@ if RUBY_ENGINE == 'opal'
11
11
  else
12
12
  require "hyperstack/internal/component"
13
13
  require "react/rails/asset_variant"
14
- variant = Hyperstack.env.production? ? 'production' : 'development'
15
- react_directory = React::Rails::AssetVariant.new({environment: variant}).react_directory
14
+ variant = Hyperstack.env.production? ? :production : :development
15
+ react_directory = React::Rails::AssetVariant.new({ variant: variant }).react_directory
16
16
  Opal.append_path react_directory.untaint
17
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyper-component
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.alpha1.5
4
+ version: 1.0.alpha1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chang
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2019-06-19 00:00:00.000000000 Z
15
+ date: 2021-03-29 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: hyper-state
@@ -20,76 +20,28 @@ dependencies:
20
20
  requirements:
21
21
  - - '='
22
22
  - !ruby/object:Gem::Version
23
- version: 1.0.alpha1.5
23
+ version: 1.0.alpha1.6
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - '='
29
29
  - !ruby/object:Gem::Version
30
- version: 1.0.alpha1.5
30
+ version: 1.0.alpha1.6
31
31
  - !ruby/object:Gem::Dependency
32
32
  name: hyperstack-config
33
33
  requirement: !ruby/object:Gem::Requirement
34
34
  requirements:
35
35
  - - '='
36
36
  - !ruby/object:Gem::Version
37
- version: 1.0.alpha1.5
37
+ version: 1.0.alpha1.6
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  requirements:
42
42
  - - '='
43
43
  - !ruby/object:Gem::Version
44
- version: 1.0.alpha1.5
45
- - !ruby/object:Gem::Dependency
46
- name: libv8
47
- requirement: !ruby/object:Gem::Requirement
48
- requirements:
49
- - - "~>"
50
- - !ruby/object:Gem::Version
51
- version: 6.7.0
52
- type: :runtime
53
- prerelease: false
54
- version_requirements: !ruby/object:Gem::Requirement
55
- requirements:
56
- - - "~>"
57
- - !ruby/object:Gem::Version
58
- version: 6.7.0
59
- - !ruby/object:Gem::Dependency
60
- name: mini_racer
61
- requirement: !ruby/object:Gem::Requirement
62
- requirements:
63
- - - "~>"
64
- - !ruby/object:Gem::Version
65
- version: 0.2.4
66
- type: :runtime
67
- prerelease: false
68
- version_requirements: !ruby/object:Gem::Requirement
69
- requirements:
70
- - - "~>"
71
- - !ruby/object:Gem::Version
72
- version: 0.2.4
73
- - !ruby/object:Gem::Dependency
74
- name: opal
75
- requirement: !ruby/object:Gem::Requirement
76
- requirements:
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: 0.11.0
80
- - - "<"
81
- - !ruby/object:Gem::Version
82
- version: 0.12.0
83
- type: :runtime
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 0.11.0
90
- - - "<"
91
- - !ruby/object:Gem::Version
92
- version: 0.12.0
44
+ version: 1.0.alpha1.6
93
45
  - !ruby/object:Gem::Dependency
94
46
  name: opal-activesupport
95
47
  requirement: !ruby/object:Gem::Requirement
@@ -130,20 +82,14 @@ dependencies:
130
82
  requirements:
131
83
  - - ">="
132
84
  - !ruby/object:Gem::Version
133
- version: 1.17.3
134
- - - "<"
135
- - !ruby/object:Gem::Version
136
- version: '2.1'
85
+ version: '0'
137
86
  type: :development
138
87
  prerelease: false
139
88
  version_requirements: !ruby/object:Gem::Requirement
140
89
  requirements:
141
90
  - - ">="
142
91
  - !ruby/object:Gem::Version
143
- version: 1.17.3
144
- - - "<"
145
- - !ruby/object:Gem::Version
146
- version: '2.1'
92
+ version: '0'
147
93
  - !ruby/object:Gem::Dependency
148
94
  name: chromedriver-helper
149
95
  requirement: !ruby/object:Gem::Requirement
@@ -164,14 +110,14 @@ dependencies:
164
110
  requirements:
165
111
  - - '='
166
112
  - !ruby/object:Gem::Version
167
- version: 1.0.alpha1.5
113
+ version: 1.0.alpha1.6
168
114
  type: :development
169
115
  prerelease: false
170
116
  version_requirements: !ruby/object:Gem::Requirement
171
117
  requirements:
172
118
  - - '='
173
119
  - !ruby/object:Gem::Version
174
- version: 1.0.alpha1.5
120
+ version: 1.0.alpha1.6
175
121
  - !ruby/object:Gem::Dependency
176
122
  name: jquery-rails
177
123
  requirement: !ruby/object:Gem::Requirement
@@ -215,7 +161,7 @@ dependencies:
215
161
  - !ruby/object:Gem::Version
216
162
  version: '0'
217
163
  - !ruby/object:Gem::Dependency
218
- name: nokogiri
164
+ name: mini_racer
219
165
  requirement: !ruby/object:Gem::Requirement
220
166
  requirements:
221
167
  - - ">="
@@ -229,7 +175,7 @@ dependencies:
229
175
  - !ruby/object:Gem::Version
230
176
  version: '0'
231
177
  - !ruby/object:Gem::Dependency
232
- name: opal-jquery
178
+ name: nokogiri
233
179
  requirement: !ruby/object:Gem::Requirement
234
180
  requirements:
235
181
  - - ">="
@@ -243,35 +189,41 @@ dependencies:
243
189
  - !ruby/object:Gem::Version
244
190
  version: '0'
245
191
  - !ruby/object:Gem::Dependency
246
- name: opal-rails
192
+ name: opal-jquery
247
193
  requirement: !ruby/object:Gem::Requirement
248
194
  requirements:
249
- - - "~>"
195
+ - - ">="
250
196
  - !ruby/object:Gem::Version
251
- version: 0.9.4
197
+ version: '0'
252
198
  type: :development
253
199
  prerelease: false
254
200
  version_requirements: !ruby/object:Gem::Requirement
255
201
  requirements:
256
- - - "~>"
202
+ - - ">="
257
203
  - !ruby/object:Gem::Version
258
- version: 0.9.4
204
+ version: '0'
259
205
  - !ruby/object:Gem::Dependency
260
- name: opal-rspec
206
+ name: opal-rails
261
207
  requirement: !ruby/object:Gem::Requirement
262
208
  requirements:
263
209
  - - ">="
264
210
  - !ruby/object:Gem::Version
265
- version: '0'
211
+ version: 0.9.4
212
+ - - "<"
213
+ - !ruby/object:Gem::Version
214
+ version: '2.0'
266
215
  type: :development
267
216
  prerelease: false
268
217
  version_requirements: !ruby/object:Gem::Requirement
269
218
  requirements:
270
219
  - - ">="
271
220
  - !ruby/object:Gem::Version
272
- version: '0'
221
+ version: 0.9.4
222
+ - - "<"
223
+ - !ruby/object:Gem::Version
224
+ version: '2.0'
273
225
  - !ruby/object:Gem::Dependency
274
- name: pry
226
+ name: pry-rescue
275
227
  requirement: !ruby/object:Gem::Requirement
276
228
  requirements:
277
229
  - - ">="
@@ -285,7 +237,7 @@ dependencies:
285
237
  - !ruby/object:Gem::Version
286
238
  version: '0'
287
239
  - !ruby/object:Gem::Dependency
288
- name: pry-rescue
240
+ name: pry-stack_explorer
289
241
  requirement: !ruby/object:Gem::Requirement
290
242
  requirements:
291
243
  - - ">="
@@ -318,14 +270,20 @@ dependencies:
318
270
  requirements:
319
271
  - - ">="
320
272
  - !ruby/object:Gem::Version
321
- version: 4.0.0
273
+ version: 5.0.0
274
+ - - "<"
275
+ - !ruby/object:Gem::Version
276
+ version: '7.0'
322
277
  type: :development
323
278
  prerelease: false
324
279
  version_requirements: !ruby/object:Gem::Requirement
325
280
  requirements:
326
281
  - - ">="
327
282
  - !ruby/object:Gem::Version
328
- version: 4.0.0
283
+ version: 5.0.0
284
+ - - "<"
285
+ - !ruby/object:Gem::Version
286
+ version: '7.0'
329
287
  - !ruby/object:Gem::Dependency
330
288
  name: rails-controller-testing
331
289
  requirement: !ruby/object:Gem::Requirement
@@ -388,14 +346,14 @@ dependencies:
388
346
  requirements:
389
347
  - - "~>"
390
348
  - !ruby/object:Gem::Version
391
- version: 1.3.6
349
+ version: 1.4.2
392
350
  type: :development
393
351
  prerelease: false
394
352
  version_requirements: !ruby/object:Gem::Requirement
395
353
  requirements:
396
354
  - - "~>"
397
355
  - !ruby/object:Gem::Version
398
- version: 1.3.6
356
+ version: 1.4.2
399
357
  - !ruby/object:Gem::Dependency
400
358
  name: timecop
401
359
  requirement: !ruby/object:Gem::Requirement
@@ -493,7 +451,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
493
451
  - !ruby/object:Gem::Version
494
452
  version: 1.3.1
495
453
  requirements: []
496
- rubygems_version: 3.0.4
454
+ rubygems_version: 3.0.8
497
455
  signing_key:
498
456
  specification_version: 4
499
457
  summary: Opal Ruby wrapper of React.js library.