isomorfeus-react 16.5.1

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 (63) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -0
  3. data/README.md +620 -0
  4. data/isomorfeus-react.gemspec +23 -0
  5. data/lib/isomorfeus-react.rb +131 -0
  6. data/lib/isomorfeus/config.rb +84 -0
  7. data/lib/isomorfeus/top_level.rb +48 -0
  8. data/lib/isomorfeus/view_helpers.rb +38 -0
  9. data/lib/lucid_app/api.rb +22 -0
  10. data/lib/lucid_app/base.rb +7 -0
  11. data/lib/lucid_app/context.rb +7 -0
  12. data/lib/lucid_app/mixin.rb +17 -0
  13. data/lib/lucid_app/native_component_constructor.rb +70 -0
  14. data/lib/lucid_component/api.rb +97 -0
  15. data/lib/lucid_component/base.rb +7 -0
  16. data/lib/lucid_component/event_handler.rb +17 -0
  17. data/lib/lucid_component/initializer.rb +12 -0
  18. data/lib/lucid_component/mixin.rb +17 -0
  19. data/lib/lucid_component/native_component_constructor.rb +131 -0
  20. data/lib/react.rb +147 -0
  21. data/lib/react/active_support_support.rb +13 -0
  22. data/lib/react/component/api.rb +226 -0
  23. data/lib/react/component/base.rb +9 -0
  24. data/lib/react/component/elements.rb +78 -0
  25. data/lib/react/component/event_handler.rb +19 -0
  26. data/lib/react/component/features.rb +47 -0
  27. data/lib/react/component/history.rb +36 -0
  28. data/lib/react/component/initializer.rb +11 -0
  29. data/lib/react/component/location.rb +15 -0
  30. data/lib/react/component/match.rb +31 -0
  31. data/lib/react/component/mixin.rb +19 -0
  32. data/lib/react/component/native_component_constructor.rb +76 -0
  33. data/lib/react/component/native_component_validate_prop.rb +37 -0
  34. data/lib/react/component/props.rb +49 -0
  35. data/lib/react/component/resolution.rb +71 -0
  36. data/lib/react/component/should_component_update.rb +14 -0
  37. data/lib/react/component/state.rb +52 -0
  38. data/lib/react/component/unsafe_api.rb +33 -0
  39. data/lib/react/context_wrapper.rb +47 -0
  40. data/lib/react/function_component/creator.rb +47 -0
  41. data/lib/react/function_component/resolution.rb +61 -0
  42. data/lib/react/function_component/runner.rb +19 -0
  43. data/lib/react/native_constant_wrapper.rb +34 -0
  44. data/lib/react/pure_component/base.rb +9 -0
  45. data/lib/react/pure_component/mixin.rb +17 -0
  46. data/lib/react/redux_component/api.rb +132 -0
  47. data/lib/react/redux_component/app_store_defaults.rb +38 -0
  48. data/lib/react/redux_component/app_store_proxy.rb +46 -0
  49. data/lib/react/redux_component/base.rb +9 -0
  50. data/lib/react/redux_component/class_store_proxy.rb +50 -0
  51. data/lib/react/redux_component/component_class_store_defaults.rb +40 -0
  52. data/lib/react/redux_component/component_instance_store_defaults.rb +41 -0
  53. data/lib/react/redux_component/initializer.rb +14 -0
  54. data/lib/react/redux_component/instance_store_proxy.rb +50 -0
  55. data/lib/react/redux_component/mixin.rb +18 -0
  56. data/lib/react/redux_component/native_component_constructor.rb +119 -0
  57. data/lib/react/redux_component/reducers.rb +53 -0
  58. data/lib/react/ref.rb +19 -0
  59. data/lib/react/synthetic_event.rb +53 -0
  60. data/lib/react/version.rb +3 -0
  61. data/lib/react_dom.rb +31 -0
  62. data/lib/react_dom_server.rb +17 -0
  63. metadata +167 -0
@@ -0,0 +1,31 @@
1
+ module React
2
+ module Component
3
+ class Match
4
+ include ::Native::Wrapper
5
+
6
+ def method_missing(prop, *args, &block)
7
+ @native.JS[:params].JS[prop]
8
+ end
9
+
10
+ def is_exact
11
+ @native.JS[:isExact]
12
+ end
13
+
14
+ def params
15
+ self
16
+ end
17
+
18
+ def path
19
+ @native.JS[:path]
20
+ end
21
+
22
+ def url
23
+ @native.JS[:url]
24
+ end
25
+
26
+ def to_n
27
+ @native
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module React
2
+ module Component
3
+ module Mixin
4
+ def self.included(base)
5
+ base.include(::Native::Wrapper)
6
+ base.extend(::React::Component::NativeComponentConstructor)
7
+ base.extend(::React::Component::NativeComponentValidateProp)
8
+ base.extend(::React::Component::ShouldComponentUpdate)
9
+ base.extend(::React::Component::EventHandler)
10
+ base.include(::React::Component::Elements)
11
+ base.include(::React::Component::API)
12
+ base.include(::React::Component::UnsafeAPI)
13
+ base.include(::React::Component::Initializer)
14
+ base.include(::React::Component::Features)
15
+ base.include(::React::Component::Resolution)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,76 @@
1
+ module React
2
+ module Component
3
+ module NativeComponentConstructor
4
+ # for should_component_update we apply ruby semantics for comparing props
5
+ # to do so, we convert the props to ruby hashes and then compare
6
+ # this makes sure, that for example rubys Nil object gets handled properly
7
+ def self.extended(base)
8
+ component_name = base.to_s
9
+ # language=JS
10
+ %x{
11
+ base.react_component = class extends React.Component {
12
+ constructor(props) {
13
+ super(props);
14
+ if (base.$default_state_defined()) {
15
+ this.state = base.$state().$to_n();
16
+ } else {
17
+ this.state = {};
18
+ };
19
+ this.__ruby_instance = base.$new(this);
20
+ var event_handlers = #{base.event_handlers};
21
+ for (var i = 0; i < event_handlers.length; i++) {
22
+ this[event_handlers[i]] = this[event_handlers[i]].bind(this);
23
+ }
24
+ var defined_refs = #{base.defined_refs};
25
+ for (var ref in defined_refs) {
26
+ if (defined_refs[ref] != null) {
27
+ this[ref] = function(element) {
28
+ #{`this.__ruby_instance`.instance_exec(React::Ref.new(`element`), `defined_refs[ref]`)}
29
+ }
30
+ this[ref] = this[ref].bind(this);
31
+ } else {
32
+ this[ref] = React.createRef();
33
+ }
34
+ }
35
+ }
36
+ static get displayName() {
37
+ return #{component_name};
38
+ }
39
+ shouldComponentUpdate(next_props, next_state) {
40
+ if (base.has_custom_should_component_update) {
41
+ return this.__ruby_instance["$should_component_update"](#{(Hash.new(next_props))}, #{Hash.new(next_state)});
42
+ } else {
43
+ var next_props_keys = Object.keys(next_props);
44
+ var this_props_keys = Object.keys(this.props);
45
+ if (next_props_keys.length !== this_props_keys.length) { return true; }
46
+
47
+ var next_state_keys = Object.keys(next_state);
48
+ var this_state_keys = Object.keys(this.state);
49
+ if (next_state_keys.length !== this_state_keys.length) { return true; }
50
+
51
+ for (var property in next_props) {
52
+ if (next_props.hasOwnProperty(property)) {
53
+ if (!this.props.hasOwnProperty(property)) { return true; };
54
+ if (property == "children") { if (next_props.children !== this.props.children) { return true; }}
55
+ else if (typeof next_props[property] !== "undefined" && typeof next_props[property]['$!='] !== "undefined" && typeof this.props[property] !== "undefined" && typeof this.props[property]['$!='] !== "undefined") {
56
+ if (#{ !! (`next_props[property]` != `this.props[property]`) }) { return true; };
57
+ } else if (next_props[property] !== this.props[property]) { return true; };
58
+ }
59
+ }
60
+ for (var property in next_state) {
61
+ if (next_state.hasOwnProperty(property)) {
62
+ if (!this.state.hasOwnProperty(property)) { return true; };
63
+ if (typeof next_state[property]['$!='] !== "undefined" && typeof this.state[property]['$!='] !== "undefined") {
64
+ if (#{ !! (`next_state[property]` != `this.state[property]`) }) { return true };
65
+ } else if (next_state[property] !== this.state[property]) { return true };
66
+ }
67
+ }
68
+ return false;
69
+ }
70
+ }
71
+ }
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,37 @@
1
+ module React
2
+ module Component
3
+ module NativeComponentValidateProp
4
+ # for should_component_update we apply ruby semantics for comparing props
5
+ # to do so, we convert the props to ruby hashes and then compare
6
+ # this makes sure, that for example rubys Nil object gets handled properly
7
+ def self.extended(base)
8
+ # language=JS
9
+ %x{
10
+ base.react_component.prototype.validateProp = function(props, propName, componentName) {
11
+ var prop_data = base.react_component.propValidations[propName];
12
+ if (!prop_data) { return true; };
13
+ var value = props[propName];
14
+ var result;
15
+ if (typeof prop_data.ruby_class != "undefined") {
16
+ result = (value.$class() == prop_data.ruby_class);
17
+ if (!result) {
18
+ return new Error('Invalid prop ' + propName + '! Expected ' + prop_data.ruby_class.$to_s() + ' but was ' + value.$class().$to_s() + '!');
19
+ }
20
+ } else if (typeof prop_data.is_a != "undefined") {
21
+ result = value["$is_a?"](prop_data.is_a);
22
+ if (!result) {
23
+ return new Error('Invalid prop ' + propName + '! Expected a child of ' + prop_data.is_a.$to_s() + '!');
24
+ }
25
+ }
26
+ if (typeof prop_data.required != "undefined") {
27
+ if (prop_data.required && (typeof props[propName] == "undefined")) {
28
+ return new Error('Prop ' + propName + ' is required but not given!');
29
+ }
30
+ }
31
+ return null;
32
+ }
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ module React
2
+ module Component
3
+ class Props
4
+ include ::Native::Wrapper
5
+
6
+ def method_missing(prop, *args, &block)
7
+ @native.JS[`Opal.React.lower_camelize(prop)`]
8
+ end
9
+
10
+ def isomorfeus_store
11
+ @native.JS[:isomorfeus_store]
12
+ end
13
+
14
+ def history
15
+ return @history if @history
16
+ return nil unless @native.JS[:history]
17
+ if @native.JS[:history].JS[:pathname]
18
+ @history = React::Component::History.new(@native.JS[:history])
19
+ else
20
+ @native.JS[:history]
21
+ end
22
+ end
23
+
24
+ def location
25
+ return @location if @location
26
+ return nil unless @native.JS[:location]
27
+ if @native.JS[:location].JS[:pathname]
28
+ @location = React::Component::Location.new(@native.JS[:location])
29
+ else
30
+ @native.JS[:location]
31
+ end
32
+ end
33
+
34
+ def match
35
+ return @match if @match
36
+ return nil unless @native.JS[:match]
37
+ if @native.JS[:match].JS[:path]
38
+ @match = React::Component::Match.new(@native.JS[:match])
39
+ else
40
+ @native.JS[:match]
41
+ end
42
+ end
43
+
44
+ def to_n
45
+ @native
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,71 @@
1
+ module React
2
+ module Component
3
+ module Resolution
4
+ def self.included(base)
5
+ base.instance_exec do
6
+ alias _react_component_resolution_original_const_missing const_missing
7
+
8
+ def const_missing(const_name)
9
+ %x{
10
+ if (typeof Opal.global[const_name] == "object") {
11
+ var new_const = #{React::NativeConstantWrapper.new(`Opal.global[const_name]`, const_name)};
12
+ #{Object.const_set(const_name, `new_const`)};
13
+ return new_const;
14
+ } else {
15
+ return #{_react_component_resolution_original_const_missing(const_name)};
16
+ }
17
+ }
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+ alias _react_component_resolution_original_method_missing method_missing
24
+
25
+ def method_missing(component_name, *args, &block)
26
+ # html tags are defined as methods, so they will not end up here.
27
+ # first check for native component and render it, we want to be fast for native components
28
+ # second check for ruby component and render it, they are a bit slower anyway
29
+ # third pass on method missing
30
+ # language=JS
31
+ %x{
32
+ var component = null;
33
+ if (typeof Opal.global[component_name] == "function") {
34
+ component = Opal.global[component_name];
35
+ }
36
+ else {
37
+ var modules = self.$class().$to_s().split("::");
38
+ var modules_length = modules.length - 1;
39
+ // modules.unshift('');
40
+ var module;
41
+ var constant;
42
+ for (var i = modules_length; i > 0; i--) {
43
+ try {
44
+ module = modules.slice(0, i).join('::')
45
+ constant = self.$class().$const_get(module).$const_get(component_name, false);
46
+ if (typeof constant.react_component == "function") {
47
+ component = constant.react_component;
48
+ break;
49
+ }
50
+ }
51
+ catch(err) {
52
+ component = null;
53
+ }
54
+ }
55
+ }
56
+ if (component) {
57
+ var props = null;
58
+
59
+ if (args.length > 0) {
60
+ props = Opal.React.to_native_react_props(args[0]);
61
+ }
62
+ Opal.React.internal_render(component, props, block);
63
+ } else {
64
+ return #{_react_component_resolution_original_method_missing(component_name, *args, block)};
65
+ }
66
+ }
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,14 @@
1
+ module React
2
+ module Component
3
+ module ShouldComponentUpdate
4
+ def self.extended(base)
5
+ base.define_singleton_method(:should_component_update?) do |&block|
6
+ `base.has_custom_should_component_update = true`
7
+ define_method(:should_component_update) do |next_props, next_state|
8
+ !!block.call(Hash.new(next_props), Hash.new(next_state))
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,52 @@
1
+ module React
2
+ module Component
3
+ class State
4
+ include ::Native::Wrapper
5
+
6
+ def method_missing(key, *args, &block)
7
+ if `args.length > 0`
8
+ new_state = `{}`
9
+ new_state.JS[(`key.endsWith('=')` ? key.chop : key)] = args[0]
10
+ if block_given?
11
+ @native.JS.setState(new_state, `function() { block.$call(); }`)
12
+ else
13
+ @native.JS.setState(new_state, `null`)
14
+ end
15
+ else
16
+ return nil if `typeof #@native.state[key] == "undefined"`
17
+ @native.JS[:state].JS[key]
18
+ end
19
+ end
20
+
21
+ def set_state(updater, &block)
22
+ new_state = `{}`
23
+ updater.keys.each do |key|
24
+ new_state.JS[key] = updater[key]
25
+ end
26
+ if block_given?
27
+ @native.JS.setState(new_state, `function() { block.$call(); }`)
28
+ else
29
+ @native.JS.setState(new_state, `null`)
30
+ end
31
+ end
32
+
33
+ def size
34
+ `Object.keys(#@native.state).length`;
35
+ end
36
+
37
+ def to_n
38
+ %x{
39
+ var new_native = {};
40
+ for (var key in #@native.state) {
41
+ if (typeof #@native.state[key].$to_n !== "undefined") {
42
+ new_native[key] = #@native.state[key].$to_n();
43
+ } else {
44
+ new_native[key] = #@native.state[key];
45
+ }
46
+ }
47
+ return new_native;
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,33 @@
1
+ module React
2
+ module Component
3
+ module UnsafeAPI
4
+ def self.included(base)
5
+ base.instance_exec do
6
+ def unsafe_component_will_mount(&block)
7
+ %x{
8
+ self.react_component.prototype.UNSAFE_componentWillMount = function() {
9
+ return #{`this.__ruby_instance`.instance_exec(&block)};
10
+ }
11
+ }
12
+ end
13
+
14
+ def unsafe_component_will_receive_props(&block)
15
+ %x{
16
+ self.react_component.prototype.UNSAFE_componentWillReceiveProps = function(next_props) {
17
+ return #{`this.__ruby_instance`.instance_exec(React::Component::Props.new(`next_props`), &block)};
18
+ }
19
+ }
20
+ end
21
+
22
+ def unsafe_component_will_update(&block)
23
+ %x{
24
+ self.react_component.prototype.UNSAFE_componentWillUpdate = function(next_props, next_state) {
25
+ return #{`this.__ruby_instance`.instance_exec(React::Component::Props.new(`next_props`), `Opal.Hash.$new(next_state)`, &block)};
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ module React
2
+ class ContextWrapper
3
+ include ::Native::Wrapper
4
+
5
+ def Consumer(*args, &block)
6
+ %x{
7
+ var children = null;
8
+ var block_result = null;
9
+ var props = null;
10
+ var react_element;
11
+
12
+ if (args.length > 0) {
13
+ props = Opal.React.to_native_react_props(args[0]);
14
+ }
15
+
16
+ var react_element = React.createElement(this.native.Consumer, props, function(value) {
17
+ if (block !== nil) {
18
+ Opal.React.render_buffer.push([]);
19
+ block_result = block.$call();
20
+ if (block_result && (block_result !== nil && (typeof block_result === "string" || typeof block_result.$$typeof === "symbol" ||
21
+ (typeof block_result.constructor !== "undefined" && block_result.constructor === Array && block_result[0] && typeof block_result[0].$$typeof === "symbol")
22
+ ))) {
23
+ Opal.React.render_buffer[Opal.React.render_buffer.length - 1].push(block_result);
24
+ }
25
+ children = Opal.React.render_buffer.pop();
26
+ if (children.length == 1) { children = children[0]; }
27
+ else if (children.length == 0) { children = null; }
28
+ }
29
+ return Opal.React.render_buffer.pop();
30
+ });
31
+ Opal.React.render_buffer[Opal.React.render_buffer.length - 1].push(react_element);
32
+ return null;
33
+ }
34
+ end
35
+
36
+ def Provider(*args, &block)
37
+ %x{
38
+ var props = null;
39
+
40
+ if (args.length > 0) {
41
+ props = Opal.React.to_native_react_props(args[0]);
42
+ }
43
+ Opal.React.internal_render(this.native.Provider, props, block);
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,47 @@
1
+ module React
2
+ module FunctionComponent
3
+ class Creator
4
+ def self.event_handler(name, &block)
5
+ %x{
6
+ Opal.React.FunctionComponent.Runner.event_handlers[name] = function(event, info) {
7
+ #{ruby_event = ::React::SyntheticEvent.new(`event`)};
8
+ #{React::FunctionComponent::Runner.new(`{}`).instance_exec(ruby_event, `info`, &block)};
9
+ }
10
+ }
11
+ end
12
+
13
+ def self.function_component(component_name, &block)
14
+
15
+ %x{
16
+ var fun = function(props) {
17
+ Opal.React.render_buffer.push([]);
18
+ Opal.React.active_components.push(Opal.React.FunctionComponent.Runner.event_handlers);
19
+ #{React::FunctionComponent::Runner.new(`props`).instance_exec(&block)};
20
+ Opal.React.active_components.pop();
21
+ return Opal.React.render_buffer.pop();
22
+ }
23
+ var const_names;
24
+ if (component_name.includes('.')) {
25
+ const_names = component_name.split('.');
26
+ } else {
27
+ const_names = [component_name];
28
+ }
29
+ var const_last = const_names.length - 1;
30
+ const_names.reduce(function(prev, curr) {
31
+ if (prev && prev[curr]) {
32
+ return prev[curr];
33
+ } else {
34
+ if (const_names.indexOf(curr) === const_last) {
35
+ prev[curr] = fun;
36
+ return prev[curr];
37
+ } else {
38
+ prev[curr] = {};
39
+ return prev[curr];
40
+ }
41
+ }
42
+ }, Opal.global);
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end