hyper-component 0.99.6 → 1.0.alpha1

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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -3
  3. data/Gemfile +4 -3
  4. data/Gemfile.lock +51 -36
  5. data/{misc/how-component-name-lookup-works.md → how-component-name-lookup-works.md} +1 -1
  6. data/hyper-component.gemspec +9 -8
  7. data/lib/hyper-component.rb +31 -43
  8. data/lib/hyperstack/component.rb +145 -0
  9. data/lib/hyperstack/component/auto-import.rb +44 -0
  10. data/lib/hyperstack/component/children.rb +40 -0
  11. data/lib/hyperstack/component/element.rb +129 -0
  12. data/lib/hyperstack/component/event.rb +78 -0
  13. data/lib/hyperstack/component/haml.rb +18 -0
  14. data/lib/hyperstack/component/isomorphic_helpers.rb +235 -0
  15. data/lib/hyperstack/component/jquery.rb +2 -0
  16. data/lib/hyperstack/component/native_library.rb +92 -0
  17. data/lib/hyperstack/component/react_api.rb +142 -0
  18. data/lib/hyperstack/component/server.rb +21 -0
  19. data/lib/hyperstack/component/version.rb +5 -0
  20. data/lib/hyperstack/ext/component/boolean.rb +14 -0
  21. data/lib/{react/ext/opal-jquery → hyperstack/ext/component}/element.rb +17 -12
  22. data/lib/{react/ext → hyperstack/ext/component}/hash.rb +0 -0
  23. data/lib/{react/to_key.rb → hyperstack/ext/component/number.rb} +0 -12
  24. data/lib/hyperstack/ext/component/object.rb +32 -0
  25. data/lib/{reactive-ruby → hyperstack/ext/component}/serializers.rb +0 -0
  26. data/lib/{react/ext → hyperstack/ext/component}/string.rb +0 -0
  27. data/lib/hyperstack/internal/component.rb +16 -0
  28. data/lib/hyperstack/internal/component/class_methods.rb +212 -0
  29. data/lib/hyperstack/internal/component/haml.rb +56 -0
  30. data/lib/hyperstack/internal/component/instance_methods.rb +92 -0
  31. data/lib/hyperstack/internal/component/props_wrapper.rb +125 -0
  32. data/lib/hyperstack/internal/component/rails.rb +11 -0
  33. data/lib/hyperstack/internal/component/rails/component_loader.rb +49 -0
  34. data/lib/hyperstack/internal/component/rails/component_mount.rb +52 -0
  35. data/lib/{reactive-ruby → hyperstack/internal/component}/rails/controller_helper.rb +0 -0
  36. data/lib/hyperstack/internal/component/rails/railtie.rb +24 -0
  37. data/lib/hyperstack/internal/component/rails/server_rendering/contextual_renderer.rb +52 -0
  38. data/lib/hyperstack/internal/component/rails/server_rendering/hyper_asset_container.rb +52 -0
  39. data/lib/hyperstack/internal/component/react_wrapper.rb +308 -0
  40. data/lib/hyperstack/internal/component/rendering_context.rb +165 -0
  41. data/lib/hyperstack/internal/component/should_component_update.rb +101 -0
  42. data/lib/hyperstack/internal/component/tags.rb +109 -0
  43. data/lib/hyperstack/internal/component/top_level_rails_component.rb +83 -0
  44. data/lib/hyperstack/internal/component/validator.rb +149 -0
  45. data/lib/react/react-source.rb +2 -2
  46. data/unmounting-objects.md +78 -0
  47. metadata +73 -85
  48. data/DOCS.md +0 -1515
  49. data/LICENSE +0 -19
  50. data/README.md +0 -49
  51. data/lib/hyper-component/jquery.rb +0 -2
  52. data/lib/rails-helpers/top_level_rails_component.rb +0 -79
  53. data/lib/react/api.rb +0 -272
  54. data/lib/react/callbacks.rb +0 -42
  55. data/lib/react/children.rb +0 -38
  56. data/lib/react/component.rb +0 -189
  57. data/lib/react/component/api.rb +0 -70
  58. data/lib/react/component/base.rb +0 -13
  59. data/lib/react/component/class_methods.rb +0 -175
  60. data/lib/react/component/dsl_instance_methods.rb +0 -23
  61. data/lib/react/component/params.rb +0 -6
  62. data/lib/react/component/props_wrapper.rb +0 -90
  63. data/lib/react/component/should_component_update.rb +0 -99
  64. data/lib/react/component/tags.rb +0 -116
  65. data/lib/react/config.rb +0 -5
  66. data/lib/react/element.rb +0 -167
  67. data/lib/react/event.rb +0 -76
  68. data/lib/react/native_library.rb +0 -87
  69. data/lib/react/object.rb +0 -15
  70. data/lib/react/ref_callback.rb +0 -31
  71. data/lib/react/rendering_context.rb +0 -149
  72. data/lib/react/server.rb +0 -19
  73. data/lib/react/state_wrapper.rb +0 -23
  74. data/lib/react/test.rb +0 -16
  75. data/lib/react/test/dsl.rb +0 -17
  76. data/lib/react/test/matchers/render_html_matcher.rb +0 -56
  77. data/lib/react/test/rspec.rb +0 -15
  78. data/lib/react/test/session.rb +0 -37
  79. data/lib/react/test/utils.rb +0 -71
  80. data/lib/react/top_level.rb +0 -110
  81. data/lib/react/top_level_render.rb +0 -30
  82. data/lib/react/validator.rb +0 -132
  83. data/lib/reactive-ruby/component_loader.rb +0 -43
  84. data/lib/reactive-ruby/isomorphic_helpers.rb +0 -233
  85. data/lib/reactive-ruby/rails.rb +0 -8
  86. data/lib/reactive-ruby/rails/component_mount.rb +0 -48
  87. data/lib/reactive-ruby/rails/railtie.rb +0 -20
  88. data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +0 -46
  89. data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +0 -46
  90. data/lib/reactive-ruby/version.rb +0 -5
  91. data/lib/reactrb/auto-import.rb +0 -27
  92. data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +0 -3
  93. data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +0 -5
  94. data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +0 -2
  95. data/misc/generators/reactive_ruby/test_app/templates/boot.rb.erb +0 -6
  96. data/misc/generators/reactive_ruby/test_app/templates/script/rails +0 -5
  97. data/misc/generators/reactive_ruby/test_app/templates/test_application.rb.erb +0 -13
  98. data/misc/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +0 -11
  99. data/misc/generators/reactive_ruby/test_app/templates/views/components/todo.rb +0 -14
  100. data/misc/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
  101. data/misc/generators/reactive_ruby/test_app/test_app_generator.rb +0 -121
  102. data/misc/hyperloop-logo-small-pink.png +0 -0
  103. data/misc/logo1.png +0 -0
  104. data/misc/logo2.png +0 -0
  105. data/misc/logo3.png +0 -0
  106. data/path_release_steps.md +0 -9
@@ -0,0 +1,56 @@
1
+ require 'hyperstack/ext/component/string'
2
+ # see hyperstack/component/haml for this is to be included.
3
+ module Hyperstack
4
+ module Internal
5
+ module Component
6
+ module HAMLTagInstanceMethods
7
+ def self.included(base)
8
+ base.const_get('HTML_TAGS').each do |tag|
9
+ if tag == 'p'
10
+ base.define_method(tag) do |*params, &children|
11
+ if children || params.count == 0 || (params.count == 1 && params.first.is_a?(Hash))
12
+ RenderingContext.render(tag, *params, &children)
13
+ else
14
+ Kernel.p(*params)
15
+ end
16
+ end
17
+ else
18
+ base.alias_method tag, tag.upcase
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ module HAMLElementInstanceMethods
25
+ def method_missing(class_name, args = {}, &new_block)
26
+ return dup.render.method_missing(class_name, args, &new_block) unless rendered?
27
+ Hyperstack::Internal::Component::RenderingContext.replace(
28
+ self,
29
+ Hyperstack::Internal::Component::RenderingContext.build do
30
+ Hyperstack::Internal::Component::RenderingContext.render(type, build_new_properties(class_name, args), &new_block)
31
+ end
32
+ )
33
+ end
34
+
35
+ def rendered?
36
+ Hyperstack::Internal::Component::RenderingContext.rendered? self
37
+ end
38
+
39
+ def haml_class_name(class_name)
40
+ class_name.gsub(/__|_/, '__' => '_', '_' => '-')
41
+ 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
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,92 @@
1
+ require "hyperstack/component/children"
2
+
3
+ module Hyperstack
4
+ module Internal
5
+ module Component
6
+ module InstanceMethods
7
+ def children
8
+ Hyperstack::Component::Children.new(`#{@__hyperstack_component_native}.props.children`)
9
+ end
10
+
11
+ def params
12
+ if @__hyperstack_component_params_wrapper.param_accessor_style == :hyperstack
13
+ raise "params are now directly accessible via instance variables.\n"\
14
+ ' to access the legacy behavior add `param_accessor_style = :legacy` '\
15
+ "to your component class\n"\
16
+ ' to access both behaviors add `param_accessor_style = :both` '\
17
+ 'to your component class'
18
+ end
19
+ @__hyperstack_component_params_wrapper
20
+ end
21
+
22
+ def props
23
+ Hash.new(`#{@__hyperstack_component_native}.props`)
24
+ end
25
+
26
+ def refs
27
+ Hash.new(`#{@__hyperstack_component_native}.refs`)
28
+ end
29
+
30
+ def dom_node
31
+ `ReactDOM.findDOMNode(#{self}.__hyperstack_component_native)` # react >= v0.15.0
32
+ end
33
+
34
+ def mounted?
35
+ `(#{self}.__hyperstack_component_is_mounted === undefined) ? false : #{self}.__hyperstack_component_is_mounted`
36
+ end
37
+
38
+ def force_update!
39
+ `#{self}.__hyperstack_component_native.forceUpdate()`
40
+ self
41
+ end
42
+
43
+ def set_state(state, &block)
44
+ set_or_replace_state_or_prop(state, 'setState', &block)
45
+ end
46
+
47
+ def set_state!(state, &block)
48
+ set_or_replace_state_or_prop(state, 'setState', &block)
49
+ `#{self}.__hyperstack_component_native.forceUpdate()`
50
+ end
51
+
52
+ private
53
+
54
+ def set_or_replace_state_or_prop(state_or_prop, method, &block)
55
+ raise "No native ReactComponent associated" unless @__hyperstack_component_native
56
+ `var state_prop_n = #{state_or_prop.shallow_to_n}`
57
+ # the state object is initalized when the ruby component is instantiated
58
+ # this is detected by self.__hyperstack_component_native.__opalInstanceInitializedState
59
+ # which is set in the native component constructor in ReactWrapper
60
+ # the setState update callback is not called when initalizing initial state
61
+ if block
62
+ %x{
63
+ if (#{@__hyperstack_component_native}.__opalInstanceInitializedState === true) {
64
+ #{@__hyperstack_component_native}[method](state_prop_n, function(){
65
+ block.$call();
66
+ });
67
+ } else {
68
+ for (var sp in state_prop_n) {
69
+ if (state_prop_n.hasOwnProperty(sp)) {
70
+ #{@__hyperstack_component_native}.state[sp] = state_prop_n[sp];
71
+ }
72
+ }
73
+ }
74
+ }
75
+ else
76
+ %x{
77
+ if (#{@__hyperstack_component_native}.__opalInstanceInitializedState === true) {
78
+ #{@__hyperstack_component_native}[method](state_prop_n);
79
+ } else {
80
+ for (var sp in state_prop_n) {
81
+ if (state_prop_n.hasOwnProperty(sp)) {
82
+ #{@__hyperstack_component_native}.state[sp] = state_prop_n[sp];
83
+ }
84
+ }
85
+ }
86
+ }
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,125 @@
1
+ require 'active_support/core_ext/string'
2
+ module Hyperstack
3
+ module Internal
4
+ module Component
5
+ class PropsWrapper
6
+ attr_reader :component
7
+
8
+ class << self
9
+ def instance_var_name_for(name)
10
+ case Hyperstack.naming_convention
11
+ when :camelize_params
12
+ name.camelize
13
+ when :prefix_params
14
+ "_#{name}"
15
+ else
16
+ name
17
+ end
18
+ end
19
+
20
+ def param_accessor_style(style = nil)
21
+ @param_accessor_style = style if style
22
+ @param_accessor_style ||=
23
+ if superclass.respond_to? :param_accessor_style
24
+ superclass.param_accessor_style
25
+ else
26
+ :hyperstack
27
+ end
28
+ end
29
+
30
+ def param_definitions
31
+ @param_definitions ||=
32
+ if superclass.respond_to? :param_definitions
33
+ superclass.param_definitions.dup
34
+ else
35
+ Hash.new
36
+ end
37
+ end
38
+
39
+ def define_param(name, param_type, aka = nil)
40
+ meth_name = aka || name
41
+ var_name = aka || instance_var_name_for(name)
42
+ param_definitions[name] = lambda do |props|
43
+ @component.instance_variable_set :"@#{var_name}", fetch_from_cache(name, param_type, props)
44
+ end
45
+ if param_type == Proc
46
+ define_method(meth_name.to_sym) do |*args, &block|
47
+ props[name].call(*args, &block) if props[name]
48
+ end
49
+ else
50
+ define_method(meth_name.to_sym) do
51
+ fetch_from_cache(name, param_type, props)
52
+ end
53
+ end
54
+ end
55
+
56
+ def define_all_others(name)
57
+ var_name = instance_var_name_for(name)
58
+ param_definitions[name] = lambda do |props|
59
+ @component.instance_variable_set :"@#{var_name}", yield(props)
60
+ end
61
+ define_method(name.to_sym) do
62
+ @_all_others_cache ||= yield(props)
63
+ end
64
+ end
65
+ end
66
+
67
+ def param_accessor_style
68
+ self.class.param_accessor_style
69
+ end
70
+
71
+ def initialize(component, incoming = nil)
72
+ @component = component
73
+ return if param_accessor_style == :legacy
74
+ self.class.param_definitions.each_value do |initializer|
75
+ instance_exec(incoming || props, &initializer)
76
+ end
77
+ end
78
+
79
+ def reload(next_props)
80
+ @_all_others_cache = nil # needed for legacy params wrapper
81
+ initialize(@component, next_props)
82
+ end
83
+
84
+ def [](prop)
85
+ props[prop]
86
+ end
87
+
88
+ private
89
+
90
+ def fetch_from_cache(name, param_type, props)
91
+ last, cached_value = cache[name]
92
+ return cached_value if last.equal?(props[name])
93
+ convert_param(name, param_type, props).tap do |value|
94
+ cache[name] = [props[name], value]
95
+ end
96
+ end
97
+
98
+ def convert_param(name, param_type, props)
99
+ if param_type.respond_to? :_react_param_conversion
100
+ param_type._react_param_conversion props[name], nil
101
+ elsif param_type.is_a?(Array) &&
102
+ param_type[0].respond_to?(:_react_param_conversion)
103
+ props[name].collect do |param|
104
+ param_type[0]._react_param_conversion param, nil
105
+ end
106
+ else
107
+ props[name]
108
+ end
109
+ end
110
+
111
+ def cache
112
+ @cache ||= Hash.new { |h, k| h[k] = [] }
113
+ end
114
+
115
+ def props
116
+ component.props
117
+ end
118
+
119
+ def value_for(name)
120
+ self[name].instance_variable_get('@value') if self[name]
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,11 @@
1
+ if defined?(Rails)
2
+ require 'action_view'
3
+ require 'react-rails'
4
+ require 'hyperstack/internal/component/rails'
5
+ require 'hyperstack/internal/component/rails/server_rendering/hyper_asset_container'
6
+ require 'hyperstack/internal/component/rails/server_rendering/contextual_renderer'
7
+ require 'hyperstack/internal/component/rails/component_mount'
8
+ require 'hyperstack/internal/component/rails/railtie'
9
+ require 'hyperstack/internal/component/rails/controller_helper'
10
+ require 'hyperstack/internal/component/rails/component_loader'
11
+ end
@@ -0,0 +1,49 @@
1
+ module Hyperstack
2
+ module Internal
3
+ module Component
4
+ module Rails
5
+ class ComponentLoader
6
+ attr_reader :v8_context
7
+ private :v8_context
8
+
9
+ def initialize(v8_context)
10
+ unless v8_context
11
+ raise ArgumentError.new('Could not obtain ExecJS runtime context')
12
+ end
13
+ @v8_context = v8_context
14
+ end
15
+
16
+ def load(file = components)
17
+ return true if loaded?
18
+ !!v8_context.eval(opal(file))
19
+ end
20
+
21
+ def load!(file = components)
22
+ return true if loaded?
23
+ self.load(file)
24
+ ensure
25
+ raise "No Hyperstack components found in #{components}" unless loaded?
26
+ end
27
+
28
+ def loaded?
29
+ !!v8_context.eval('Opal.Hyperstack !== undefined')
30
+ rescue ::ExecJS::Error
31
+ false
32
+ end
33
+
34
+ private
35
+
36
+ def components
37
+ opts = ::Rails.configuration.react.server_renderer_options
38
+ return opts[:files].first.gsub(/.js$/,'') if opts && opts[:files]
39
+ 'components'
40
+ end
41
+
42
+ def opal(file)
43
+ Opal::Sprockets.load_asset(file)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,52 @@
1
+ module Hyperstack
2
+ module Internal
3
+ module Component
4
+ module Rails
5
+ class ComponentMount < React::Rails::ComponentMount
6
+ attr_accessor :controller
7
+
8
+ def setup(controller)
9
+ self.controller = controller
10
+ end
11
+
12
+ def react_component(name, props = {}, options = {}, &block)
13
+ if options[:prerender] || [:on, 'on', true].include?(Hyperstack.prerendering)
14
+ options = context_initializer_options(options, name)
15
+ end
16
+ props = serialized_props(props, name, controller)
17
+ result = super(top_level_name, props, options, &block).gsub("\n","")
18
+ result = result.gsub(/(<script.*<\/script>)<\/div>$/,'</div>\1').html_safe
19
+ result + footers
20
+ end
21
+
22
+ private
23
+
24
+ def context_initializer_options(options, name)
25
+ options[:prerender] = {options[:prerender] => true} unless options[:prerender].is_a? Hash
26
+ existing_context_initializer = options[:prerender][:context_initializer]
27
+
28
+ options[:prerender][:context_initializer] = lambda do |ctx|
29
+ Hyperstack::Component::IsomorphicHelpers.load_context(ctx, controller, name)
30
+ existing_context_initializer.call(ctx) if existing_context_initializer
31
+ end
32
+
33
+ options
34
+ end
35
+
36
+ def serialized_props(props, name, controller)
37
+ { render_params: props, component_name: name,
38
+ controller: controller.class.name.gsub(/Controller$/,"") }.react_serializer
39
+ end
40
+
41
+ def top_level_name
42
+ 'Hyperstack.Internal.Component.TopLevelRailsComponent'
43
+ end
44
+
45
+ def footers
46
+ Hyperstack::Component::IsomorphicHelpers.prerender_footers(controller)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+ module Hyperstack
2
+ module Internal
3
+ module Component
4
+ module Rails
5
+ class Railtie < ::Rails::Railtie
6
+ config.before_configuration do |app|
7
+ app.config.assets.enabled = true
8
+ app.config.assets.paths << ::Rails.root.join('app', 'views').to_s
9
+ app.config.react.server_renderer = ServerRendering::ContextualRenderer
10
+ app.config.react.view_helper_implementation = ComponentMount
11
+ ServerRendering::ContextualRenderer.asset_container_class = ServerRendering::HyperAssetContainer
12
+ end
13
+ config.after_initialize do
14
+ class ::HyperstackController < ::ApplicationController
15
+ def action_missing(_name)
16
+ render_component
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ module Hyperstack
2
+ module Internal
3
+ module Component
4
+ module Rails
5
+ module ServerRendering
6
+ def self.context_instance_name
7
+ '@context'
8
+ end
9
+
10
+ def self.context_instance_for(context)
11
+ context.instance_variable_get(context_instance_name)
12
+ end
13
+
14
+ class ContextualRenderer < React::ServerRendering::BundleRenderer
15
+ def initialize(options = {})
16
+ super(options)
17
+ ComponentLoader.new(v8_context).load
18
+ end
19
+
20
+ def before_render(*args)
21
+ # the base class clears the log history... we don't want that as it is taken
22
+ # care of in IsomorphicHelpers.load_context
23
+ end
24
+
25
+ def render(component_name, props, prerender_options)
26
+ if prerender_options.is_a?(Hash)
27
+ if !v8_runtime? && prerender_options[:context_initializer]
28
+ raise React::ServerRendering::PrerenderError.new(component_name, props, "you must use 'mini_racer' with the prerender[:context] option") unless v8_runtime?
29
+ else
30
+ prerender_options[:context_initializer].call v8_context
31
+ prerender_options = prerender_options[:static] ? :static : true
32
+ end
33
+ end
34
+
35
+ super(component_name, props, prerender_options)
36
+ end
37
+
38
+ private
39
+
40
+ def v8_runtime?
41
+ ExecJS.runtime.name == 'mini_racer (V8)'
42
+ end
43
+
44
+ def v8_context
45
+ @v8_context ||= ServerRendering.context_instance_for(@context)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end