isomorfeus-react 16.5.1

Sign up to get free protection for your applications and to get access to all the features.
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