isomorfeus-react 16.6.8 → 16.8.0

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