isomorfeus-react 16.6.8 → 16.8.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -413
  3. data/lib/isomorfeus-react-base.rb +55 -0
  4. data/lib/isomorfeus-react-component.rb +20 -0
  5. data/lib/isomorfeus-react-lucid.rb +39 -0
  6. data/lib/isomorfeus-react-material-ui.rb +41 -0
  7. data/lib/isomorfeus-react-redux-component.rb +25 -0
  8. data/lib/isomorfeus-react.rb +4 -101
  9. data/lib/isomorfeus/config.rb +3 -8
  10. data/lib/isomorfeus/top_level_browser.rb +1 -1
  11. data/lib/lucid_app/api.rb +1 -12
  12. data/lib/lucid_app/mixin.rb +1 -0
  13. data/lib/lucid_app/native_component_constructor.rb +10 -0
  14. data/lib/lucid_component/api.rb +1 -1
  15. data/lib/lucid_component/initializer.rb +5 -5
  16. data/lib/lucid_component/mixin.rb +1 -0
  17. data/lib/lucid_component/native_component_constructor.rb +13 -3
  18. data/lib/lucid_material/app/base.rb +9 -0
  19. data/lib/lucid_material/app/mixin.rb +20 -0
  20. data/lib/lucid_material/app/native_component_constructor.rb +116 -0
  21. data/lib/lucid_material/component/api.rb +19 -0
  22. data/lib/lucid_material/component/base.rb +9 -0
  23. data/lib/lucid_material/component/mixin.rb +21 -0
  24. data/lib/lucid_material/component/native_component_constructor.rb +158 -0
  25. data/lib/react.rb +13 -5
  26. data/lib/react/children.rb +35 -0
  27. data/lib/react/component/api.rb +5 -91
  28. data/lib/react/component/callbacks.rb +103 -0
  29. data/lib/react/component/elements.rb +3 -23
  30. data/lib/react/component/features.rb +12 -29
  31. data/lib/react/component/initializer.rb +2 -2
  32. data/lib/react/component/mixin.rb +1 -0
  33. data/lib/react/component/native_component_constructor.rb +7 -0
  34. data/lib/react/component/props.rb +13 -1
  35. data/lib/react/component/resolution.rb +14 -15
  36. data/lib/react/component/styles.rb +23 -0
  37. data/lib/react/context_wrapper.rb +4 -0
  38. data/lib/react/function_component/api.rb +83 -0
  39. data/lib/react/function_component/base.rb +9 -0
  40. data/lib/react/function_component/creator.rb +19 -65
  41. data/lib/react/function_component/event_handler.rb +13 -0
  42. data/lib/react/function_component/mixin.rb +14 -0
  43. data/lib/react/function_component/resolution.rb +17 -15
  44. data/lib/react/memo_component/base.rb +9 -0
  45. data/lib/react/memo_component/creator.rb +32 -0
  46. data/lib/react/memo_component/mixin.rb +14 -0
  47. data/lib/react/native_constant_wrapper.rb +1 -11
  48. data/lib/react/pure_component/mixin.rb +2 -0
  49. data/lib/react/redux_component/api.rb +1 -93
  50. data/lib/react/redux_component/initializer.rb +5 -5
  51. data/lib/react/redux_component/mixin.rb +1 -0
  52. data/lib/react/redux_component/native_component_constructor.rb +13 -3
  53. data/lib/react/redux_component/reducers.rb +29 -35
  54. data/lib/react/ref.rb +4 -0
  55. data/lib/react/version.rb +1 -1
  56. data/lib/react_dom.rb +9 -3
  57. metadata +70 -8
  58. data/lib/lucid_router.rb +0 -18
  59. data/lib/react/function_component/runner.rb +0 -19
@@ -0,0 +1,103 @@
1
+ module React
2
+ module Component
3
+ module Callbacks
4
+ def self.included(base)
5
+ base.instance_exec do
6
+ def component_did_catch(&block)
7
+ # TODO convert error and info
8
+ %x{
9
+ var fun = function(error, info) {
10
+ Opal.React.active_redux_components.push(this.__ruby_instance);
11
+ #{`this.__ruby_instance`.instance_exec(`error`, `info`, &block)};
12
+ Opal.React.active_redux_components.pop();
13
+ }
14
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.componentDidCatch = fun; }
15
+ else { self.react_component.prototype.componentDidCatch = fun; }
16
+ }
17
+ end
18
+
19
+ def component_did_mount(&block)
20
+ %x{
21
+ var fun = function() {
22
+ Opal.React.active_redux_components.push(this.__ruby_instance);
23
+ #{`this.__ruby_instance`.instance_exec(&block)};
24
+ Opal.React.active_redux_components.pop();
25
+ }
26
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.componentDidMount = fun; }
27
+ else { self.react_component.prototype.componentDidMount = fun; }
28
+ }
29
+ end
30
+
31
+ def component_did_update(&block)
32
+ %x{
33
+ var fun = function(prev_props, prev_state, snapshot) {
34
+ Opal.React.active_redux_components.push(this.__ruby_instance);
35
+ #{`this.__ruby_instance`.instance_exec(`Opal.React.Component.Props.$new(prev_props)`,
36
+ `Opal.React.Component.State.$new({state: prev_state})`,
37
+ `snapshot`, &block)};
38
+ Opal.React.active_redux_components.pop();
39
+ }
40
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.componentDidUpdate = fun; }
41
+ else { self.react_component.prototype.componentDidUpdate = fun; }
42
+ }
43
+ end
44
+
45
+ def component_will_unmount(&block)
46
+ %x{
47
+ var fun = function() {
48
+ if (typeof this.unsubscriber === "function") { this.unsubscriber(); };
49
+ Opal.React.active_redux_components.push(this.__ruby_instance);
50
+ #{`this.__ruby_instance`.instance_exec(&block)};
51
+ Opal.React.active_redux_components.pop();
52
+ }
53
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.componentWillUnmount = fun; }
54
+ else { self.react_component.prototype.componentWillUnmount = fun; }
55
+ }
56
+ end
57
+
58
+ def get_derived_state_from_error(&block)
59
+ # TODO convert error
60
+ %x{
61
+ var fun = function(error) {
62
+ var result = #{`this.__ruby_instance`.instance_exec(`error`, &block)};
63
+ if (result === null) { return null; }
64
+ if (typeof result.$to_n === 'function') { return result.$to_n() }
65
+ return result;
66
+ }
67
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.getDerivedStateFromError = fun; }
68
+ else { self.react_component.prototype.getDerivedStateFromError = fun; }
69
+ }
70
+ end
71
+
72
+ def get_derived_state_from_props(&block)
73
+ %x{
74
+ var fun = function(props, state) {
75
+ Opal.React.active_redux_components.push(this.__ruby_instance);
76
+ #{`this.__ruby_instance`.instance_exec(`Opal.React.Component.Props.$new(props)`,
77
+ `Opal.React.Component.State.$new({state: state})`,
78
+ &block)};
79
+ Opal.React.active_redux_components.pop();
80
+ }
81
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.getDerivedStateFromProps = fun; }
82
+ else { self.react_component.prototype.getDerivedStateFromProps = fun; }
83
+ }
84
+ end
85
+
86
+ def get_snapshot_before_update(&block)
87
+ %x{
88
+ var fun = function(prev_props, prev_state) {
89
+ Opal.React.active_redux_components.push(this.__ruby_instance);
90
+ #{`this.__ruby_instance`.instance_exec(`Opal.React.Component.Props.$new(prev_props)`,
91
+ `Opal.React.Component.State.$new({state: prev_state})`,
92
+ &block)};
93
+ Opal.React.active_redux_components.pop();
94
+ }
95
+ if (self.lucid_react_component) { self.lucid_react_component.prototype.getSnapshotBeforeUpdate = fun; }
96
+ else { self.react_component.prototype.getSnapshotBeforeUpdate = fun; }
97
+ }
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -2,6 +2,7 @@ module React
2
2
  module Component
3
3
  module Elements
4
4
  # https://www.w3.org/TR/html52/fullindex.html#index-elements
5
+ # https://www.w3.org/TR/SVG11/eltindex.html
5
6
  SUPPORTED_HTML_AND_SVG_ELEMENTS = %w[
6
7
  a abbr address area article aside audio
7
8
  b base bdi bdo blockquote body br button
@@ -24,10 +25,6 @@ module React
24
25
  u ul
25
26
  var video
26
27
  wbr
27
- ] +
28
- # https://www.w3.org/TR/SVG11/eltindex.html
29
- # elements listed above not mentioned a second time
30
- %w[
31
28
  altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform
32
29
  circle clipPath color-profile cursor
33
30
  defs desc
@@ -50,29 +47,12 @@ module React
50
47
  view vkern
51
48
  ]
52
49
 
53
-
54
50
  SUPPORTED_HTML_AND_SVG_ELEMENTS.each do |element|
55
51
  define_method(element) do |*args, &block|
56
- %x{
57
- if (args.length > 0) {
58
- var last_arg = args[args.length - 1];
59
- if (typeof last_arg === 'string' || last_arg instanceof String) {
60
- if (args.length === 1) { Opal.React.internal_render(element, null, last_arg, null); }
61
- else { Opal.React.internal_render(element, args[0], last_arg, null); }
62
- } else { Opal.React.internal_render(element, args[0], null, block); }
63
- } else { Opal.React.internal_render(element, null, null, block); }
64
- }
52
+ `Opal.React.internal_prepare_args_and_render(element, args, block)`
65
53
  end
66
54
  define_method(`element.toUpperCase()`) do |*args, &block|
67
- %x{
68
- if (args.length > 0) {
69
- var last_arg = args[args.length - 1];
70
- if (typeof last_arg === 'string' || last_arg instanceof String) {
71
- if (args.length === 1) { Opal.React.internal_render(element, null, last_arg, null); }
72
- else { Opal.React.internal_render(element, args[0], last_arg, null); }
73
- } else { Opal.React.internal_render(element, args[0], null, block); }
74
- } else { Opal.React.internal_render(element, null, null, block); }
75
- }
55
+ `Opal.React.internal_prepare_args_and_render(element, args, block)`
76
56
  end
77
57
  end
78
58
  end
@@ -2,18 +2,17 @@ module React
2
2
  module Component
3
3
  module Features
4
4
  def Fragment(*args, &block)
5
- %x{
6
- if (args.length > 0) {
7
- var last_arg = args[args.length - 1];
8
- if (typeof last_arg === 'string' || last_arg instanceof String) {
9
- if (args.length === 1) { Opal.React.internal_render(React.Fragment, null, last_arg, null); }
10
- else { Opal.React.internal_render(Opal.global.React.Fragment, args[0], last_arg, null); }
11
- } else { Opal.React.internal_render(Opal.global.React.Fragment, args[0], null, block); }
12
- } else { Opal.React.internal_render(Opal.global.React.Fragment, null, null, block); }
13
- }
5
+ `Opal.React.internal_prepare_args_and_render(Opal.global.React.Fragment, args, block)`
14
6
  end
15
7
 
16
- def Portal(dom_node, &block)
8
+ def Portal(element_or_query, &block)
9
+ if `(typeof element_or_query === 'string')` || (`(typeof element_or_query.$class === 'function')` && element_or_query.class == String)
10
+ element = `document.body.querySelector(element_or_query)`
11
+ elsif `(typeof element_or_query.$is_a === 'function')` && element_or_query.is_a?(Browser::DOM::Node)
12
+ element = element_or_query.to_n
13
+ else
14
+ element = element_or_query
15
+ end
17
16
  %x{
18
17
  var children = null;
19
18
  var block_result = null;
@@ -27,34 +26,18 @@ module React
27
26
  Opal.React.render_buffer[Opal.React.render_buffer.length - 1].push(block_result);
28
27
  }
29
28
  }
30
- var react_element = Opal.global.React.createPortal(Opal.React.render_buffer.pop(), dom_node);
29
+ var react_element = Opal.global.React.createPortal(Opal.React.render_buffer.pop(), element);
31
30
  Opal.React.render_buffer[Opal.React.render_buffer.length - 1].push(react_element);
32
31
  return null;
33
32
  }
34
33
  end
35
34
 
36
35
  def StrictMode(*args, &block)
37
- %x{
38
- if (args.length > 0) {
39
- var last_arg = args[args.length - 1];
40
- if (typeof last_arg === 'string' || last_arg instanceof String) {
41
- if (args.length === 1) { Opal.React.internal_render(Opal.global.React.StrictMode, null, last_arg, null); }
42
- else { Opal.React.internal_render(Opal.global.React.StrictMode, args[0], last_arg, null); }
43
- } else { Opal.React.internal_render(Opal.global.React.StrictMode, args[0], null, block); }
44
- } else { Opal.React.internal_render(Opal.global.React.StrictMode, null, null, block); }
45
- }
36
+ `Opal.React.internal_prepare_args_and_render(Opal.global.React.StrictMode, args, block)`
46
37
  end
47
38
 
48
39
  def Suspense(*args, &block)
49
- %x{
50
- if (args.length > 0) {
51
- var last_arg = args[args.length - 1];
52
- if (typeof last_arg === 'string' || last_arg instanceof String) {
53
- if (args.length === 1) { Opal.React.internal_render(Opal.global.React.Suspense, null, last_arg, null); }
54
- else { Opal.React.internal_render(Opal.global.React.Suspense, args[0], last_arg, null); }
55
- } else { Opal.React.internal_render(Opal.global.React.Suspense, args[0], null, block); }
56
- } else { Opal.React.internal_render(Opal.global.React.Suspense, null, null, block); }
57
- }
40
+ `Opal.React.internal_prepare_args_and_render(Opal.global.React.Suspense, args, block)`
58
41
  end
59
42
  end
60
43
  end
@@ -3,8 +3,8 @@ module React
3
3
  module Initializer
4
4
  def initialize(native_component)
5
5
  @native = native_component
6
- @props = ::React::Component::Props.new(@native.JS[:props])
7
- @state = ::React::Component::State.new(@native)
6
+ @props = `Opal.React.Component.Props.$new(#@native.props)`
7
+ @state = `Opal.React.Component.State.$new(#@native)`
8
8
  end
9
9
  end
10
10
  end
@@ -9,6 +9,7 @@ module React
9
9
  base.extend(::React::Component::EventHandler)
10
10
  base.include(::React::Component::Elements)
11
11
  base.include(::React::Component::API)
12
+ base.include(::React::Component::Callbacks)
12
13
  base.include(::React::Component::UnsafeAPI)
13
14
  base.include(::React::Component::Initializer)
14
15
  base.include(::React::Component::Features)
@@ -36,6 +36,13 @@ module React
36
36
  static get displayName() {
37
37
  return #{component_name};
38
38
  }
39
+ render() {
40
+ Opal.React.render_buffer.push([]);
41
+ Opal.React.active_components.push(this);
42
+ #{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
43
+ Opal.React.active_components.pop();
44
+ return Opal.React.render_buffer.pop();
45
+ }
39
46
  shouldComponentUpdate(next_props, next_state) {
40
47
  if (base.has_custom_should_component_update) {
41
48
  return this.__ruby_instance["$should_component_update"](#{(Hash.new(next_props))}, #{Hash.new(next_state)});
@@ -4,13 +4,25 @@ module React
4
4
  include ::Native::Wrapper
5
5
 
6
6
  def method_missing(prop, *args, &block)
7
- @native.JS[`Opal.React.lower_camelize(prop)`]
7
+ %x{
8
+ var prop_name = Opal.React.lower_camelize(prop);
9
+ if (typeof #@native[prop_name] === 'undefined') {
10
+ return #{nil};
11
+ } else {
12
+ return #@native[prop_name];
13
+ }
14
+ }
15
+ end
16
+
17
+ def classes
18
+ @classes ||= `Opal.React.Component.Styles.$new(#@native.classes)`
8
19
  end
9
20
 
10
21
  def isomorfeus_store
11
22
  @native.JS[:isomorfeus_store]
12
23
  end
13
24
 
25
+ # for router convenience
14
26
  def history
15
27
  return @history if @history
16
28
  return nil unless @native.JS[:history]
@@ -34,42 +34,41 @@ module React
34
34
  var component_type = typeof Opal.global[component_name];
35
35
  if (component_type === "function" || component_type === "object") {
36
36
  component = Opal.global[component_name];
37
- }
38
- else {
37
+ } else {
39
38
  var modules = self.$class().$to_s().split("::");
40
39
  var modules_length = modules.length - 1;
41
- // modules.unshift('');
42
40
  var module;
43
41
  var constant;
44
42
  for (var i = modules_length; i > 0; i--) {
45
43
  try {
46
44
  module = modules.slice(0, i).join('::')
47
45
  constant = self.$class().$const_get(module).$const_get(component_name, false);
48
- component_type = typeof constant.react_component;
49
- if (component_type === "function" || component_type === "object") {
46
+ if (typeof constant.react_component !== 'undefined') {
50
47
  component = constant.react_component;
51
48
  break;
52
49
  }
53
- }
54
- catch(err) {
50
+ } catch(err) {
55
51
  component = null;
56
52
  }
57
53
  }
54
+ if (!component) {
55
+ try {
56
+ constant = Opal.Object.$const_get(component_name);
57
+ if (typeof constant.react_component !== 'undefined') {
58
+ component = constant.react_component;
59
+ }
60
+ } catch(err) {
61
+ component = null
62
+ }
63
+ }
58
64
  }
59
65
  if (component) {
60
- if (args.length > 0) {
61
- var last_arg = args[args.length - 1];
62
- if (typeof last_arg === 'string' || last_arg instanceof String) {
63
- if (args.length === 1) { Opal.React.internal_render(component, null, last_arg, null); }
64
- else { Opal.React.internal_render(component, args[0], last_arg, null); }
65
- } else { Opal.React.internal_render(component, args[0], null, block); }
66
- } else { Opal.React.internal_render(component, null, null, block); }
66
+ Opal.React.internal_prepare_args_and_render(component, args, block);
67
67
  } else {
68
68
  return #{_react_component_resolution_original_method_missing(component_name, *args, block)};
69
69
  }
70
70
  }
71
71
  end
72
-
73
72
  end
74
73
  end
75
74
  end
@@ -0,0 +1,23 @@
1
+ module React
2
+ module Component
3
+ class Styles
4
+ def initialize(native)
5
+ @native = native
6
+ end
7
+
8
+ def method_missing(prop, *args, &block)
9
+ %x{
10
+ if (typeof #@native[prop] === 'undefined') {
11
+ return #{nil};
12
+ } else {
13
+ return #@native[prop];
14
+ }
15
+ }
16
+ end
17
+
18
+ def to_n
19
+ @native
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,10 @@ module React
2
2
  class ContextWrapper
3
3
  include ::Native::Wrapper
4
4
 
5
+ def is_wrapped_context
6
+ true
7
+ end
8
+
5
9
  def Consumer(*args, &block)
6
10
  %x{
7
11
  var children = null;
@@ -0,0 +1,83 @@
1
+ module React
2
+ module FunctionComponent
3
+ module API
4
+ attr_accessor :props
5
+
6
+ def initialize(props)
7
+ @props = ::React::Component::Props.new(props)
8
+ end
9
+
10
+ def use_callback(deps, &block)
11
+ %x{
12
+ Opal.global.React.useCallback(function() {
13
+ #{block.call}
14
+ }, deps);
15
+ }
16
+ end
17
+
18
+ def use_context(context)
19
+ `(typeof context.$is_wrapped_context !== 'undefined')` ? context.to_n : context
20
+ `Opal.global.React.useContext(native_context)`
21
+ end
22
+
23
+ def use_debug_value(value)
24
+ `Opal.global.React.useDebugValue(value)`
25
+ end
26
+
27
+ def use_effect(&block)
28
+ %x{
29
+ Opal.global.React.useEffect(function() {
30
+ #{block.call}
31
+ });
32
+ }
33
+ end
34
+
35
+ def use_imperative_handle(ref, *deps, &block)
36
+ native_ref = `(typeof ref.$is_wrapped_ref !== 'undefined')` ? ref.to_n : ref
37
+ %x{
38
+ Opal.global.React.useImperativeHandle(native_ref, function() {
39
+ #{block.call}
40
+ }, deps);
41
+ }
42
+ end
43
+
44
+ def use_layout_effect(&block)
45
+ %x{
46
+ Opal.global.React.useLayoutEffect(function() {
47
+ #{block.call}
48
+ });
49
+ }
50
+ end
51
+
52
+ def use_memo(*deps, &block)
53
+ %x{
54
+ Opal.global.React.useMemo(function() {
55
+ #{block.call}
56
+ }, deps);
57
+ }
58
+ end
59
+
60
+ def use_reducer(inital_state, &block)
61
+ state = nil
62
+ dispatcher = nil
63
+ %x{
64
+ [state, dispatcher] = Opal.global.React.useReducer(function(state, action) {
65
+ #{block.call(state, action)}
66
+ }, initial_state);
67
+ }
68
+ [state, proc { |arg| `dispatcher(arg)` }]
69
+ end
70
+
71
+ def use_ref(initial_value)
72
+ React::Ref.new(`Opal.global.React.useRef(initial_value)`)
73
+ end
74
+
75
+ def use_state(initial_value)
76
+ initial = nil
77
+ setter = nil
78
+ `[initial, setter] = Opal.global.React.useState(initial_value);`
79
+ [initial, proc { |arg| `setter(arg)` }]
80
+ end
81
+ end
82
+ end
83
+ end