isomorfeus-react 16.13.10 → 16.13.11

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -10
  3. data/lib/isomorfeus-react-native.rb +5 -0
  4. data/lib/isomorfeus-react-paper.rb +4 -0
  5. data/lib/isomorfeus-react.rb +6 -4
  6. data/lib/isomorfeus/props/validator.rb +2 -2
  7. data/lib/isomorfeus/{react_config.rb → react/config.rb} +0 -0
  8. data/lib/isomorfeus/react/memcached_component_cache.rb +19 -0
  9. data/lib/isomorfeus/react/redis_component_cache.rb +19 -0
  10. data/lib/isomorfeus/{thread_local_component_cache.rb → react/thread_local_component_cache.rb} +0 -0
  11. data/lib/isomorfeus_react/lucid_app/mixin.rb +1 -0
  12. data/lib/isomorfeus_react/lucid_app/native_component_constructor.rb +0 -1
  13. data/lib/isomorfeus_react/lucid_component/api.rb +0 -27
  14. data/lib/isomorfeus_react/lucid_component/mixin.rb +1 -0
  15. data/lib/isomorfeus_react/lucid_component/styles_api.rb +34 -0
  16. data/lib/isomorfeus_react/lucid_func/mixin.rb +1 -0
  17. data/lib/isomorfeus_react/react/function_component/api.rb +7 -6
  18. data/lib/isomorfeus_react_material/lucid_material/app/mixin.rb +1 -0
  19. data/lib/isomorfeus_react_material/lucid_material/app/native_component_constructor.rb +0 -1
  20. data/lib/isomorfeus_react_material/lucid_material/component/mixin.rb +1 -0
  21. data/lib/isomorfeus_react_material/lucid_material/func/mixin.rb +1 -0
  22. data/lib/isomorfeus_react_paper/lucid_paper/app/base.rb +9 -0
  23. data/lib/isomorfeus_react_paper/lucid_paper/app/mixin.rb +19 -0
  24. data/lib/isomorfeus_react_paper/lucid_paper/app/native_component_constructor.rb +32 -0
  25. data/lib/isomorfeus_react_paper/lucid_paper/component/base.rb +9 -0
  26. data/lib/isomorfeus_react_paper/lucid_paper/component/mixin.rb +18 -0
  27. data/lib/isomorfeus_react_paper/lucid_paper/component/native_component_constructor.rb +25 -0
  28. data/lib/isomorfeus_react_paper/lucid_paper/func/base.rb +9 -0
  29. data/lib/isomorfeus_react_paper/lucid_paper/func/mixin.rb +14 -0
  30. data/lib/isomorfeus_react_paper/lucid_paper/func/native_component_constructor.rb +71 -0
  31. data/lib/react.rb +6 -5
  32. data/lib/react/component/api.rb +5 -4
  33. data/lib/react/version.rb +1 -1
  34. data/lib/react_native/component/elements.rb +203 -0
  35. data/lib/react_native/lucid_app/react_native_component_constructor.rb +51 -0
  36. data/lib/react_native/lucid_component/react_native_component_constructor.rb +37 -0
  37. data/lib/react_native/lucid_func/react_native_component_constructor.rb +82 -0
  38. data/lib/react_native/react.rb +120 -0
  39. metadata +69 -22
@@ -0,0 +1,9 @@
1
+ module LucidPaper
2
+ module Func
3
+ class Base
4
+ def self.inherited(base)
5
+ base.include(::LucidPaper::Func::Mixin)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module LucidPaper
2
+ module Func
3
+ module Mixin
4
+ def self.included(base)
5
+ base.include(::React::Component::Elements)
6
+ base.include(::React::Component::Features)
7
+ base.include(::LucidFunc::Initializer)
8
+ base.include(::React::FunctionComponent::Api)
9
+ base.extend(::LucidPaper::Func::NativeComponentConstructor)
10
+ base.include(::LucidComponent::Api)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,71 @@
1
+ module LucidPaper
2
+ module Func
3
+ module NativeComponentConstructor
4
+ def self.extended(base)
5
+ component_name = "#{base.to_s}Wrapper"
6
+ %x{
7
+ base.store_updates = true;
8
+ base.equality_checker = null;
9
+ base.instance_init = function(initial) {
10
+ let ruby_state = { instance: #{base.new(`{}`)} };
11
+ ruby_state.instance.__ruby_instance = ruby_state.instance;
12
+ ruby_state.instance.data_access = function() { return this.props.store; }
13
+ ruby_state.instance.data_access.bind(ruby_state.instance);
14
+ return ruby_state;
15
+ }
16
+ base.instance_reducer = function(state, action) { return state; }
17
+ base.react_component = Opal.global.React.memo(function(props) {
18
+ const og = Opal.global;
19
+ const oper = Opal.React;
20
+ oper.render_buffer.push([]);
21
+ // console.log("function pushed", oper.render_buffer, oper.render_buffer.toString());
22
+ // Lucid functionality
23
+ let store;
24
+ if (base.store_updates) { store = og.React.useContext(og.LucidApplicationContext); }
25
+ // prepare Ruby instance
26
+ const [__ruby_state, __ruby_dispatch] = og.React.useReducer(base.instance_reducer, null, base.instance_init);
27
+ const __ruby_instance = __ruby_state.instance;
28
+ __ruby_instance.props = Object.assign({}, props);
29
+ __ruby_instance.props.store = store;
30
+ __ruby_instance.props.theme = Opal.global.Paper.useTheme();
31
+ oper.active_components.push(__ruby_instance);
32
+ oper.active_redux_components.push(__ruby_instance);
33
+ let block_result = #{`__ruby_instance`.instance_exec(&`base.render_block`)};
34
+ if (block_result && block_result !== nil) { oper.render_block_result(block_result); }
35
+ oper.active_redux_components.pop();
36
+ oper.active_components.pop();
37
+ // console.log("function popping", oper.render_buffer, oper.render_buffer.toString());
38
+ let result = oper.render_buffer.pop();
39
+ return (result.length === 1) ? result[0] : result;
40
+ }, base.equality_checker);
41
+ base.react_component.displayName = #{component_name};
42
+ }
43
+
44
+ base_module = base.to_s.deconstantize
45
+ if base_module != ''
46
+ base_module.constantize.define_singleton_method(base.to_s.demodulize) do |*args, &block|
47
+ `Opal.React.internal_prepare_args_and_render(#{base}.react_component, args, block)`
48
+ end
49
+ else
50
+ Object.define_method(base.to_s) do |*args, &block|
51
+ `Opal.React.internal_prepare_args_and_render(#{base}.react_component, args, block)`
52
+ end
53
+ end
54
+
55
+ def props_are_equal?(&block)
56
+ %x{
57
+ base.equality_checker = function (prev_props, next_props) {
58
+ var prev_ruby_props = Opal.React.Component.Props.$new({props: prev_props});
59
+ var next_ruby_props = Opal.React.Component.Props.$new({props: next_props});
60
+ return #{block.call(`prev_ruby_props`, `next_ruby_props`)};
61
+ }
62
+ }
63
+ end
64
+
65
+ def render(&block)
66
+ `base.render_block = #{block}`
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/react.rb CHANGED
@@ -135,11 +135,12 @@ module React
135
135
  let ruby_event = self.native_to_ruby_event(event);
136
136
  #{`active_c.__ruby_instance`.instance_exec(`ruby_event`, `info`, &`value`)};
137
137
  }
138
- } else if (type === "object" && typeof value.$call === "function" ) {
138
+ } else if (type === "object" && typeof value.m === "object" && typeof value.m.$call === "function" ) {
139
139
  if (!value.react_event_handler_function) {
140
140
  value.react_event_handler_function = function(event, info) {
141
141
  let ruby_event = self.native_to_ruby_event(event);
142
- value.$call(ruby_event, info)
142
+ if (value.a.length > 0) { value.m.$call.apply(value.m, [ruby_event, info].concat(value.a)); }
143
+ else { value.m.$call(ruby_event, info); }
143
144
  };
144
145
  }
145
146
  result[self.lower_camelize(key)] = value.react_event_handler_function;
@@ -161,7 +162,7 @@ module React
161
162
  if (!method_ref.react_event_handler_function) {
162
163
  method_ref.react_event_handler_function = function(event, info) {
163
164
  let ruby_event = self.native_to_ruby_event(event);
164
- method_ref.$call(ruby_event, info)
165
+ method_ref.m.$call(ruby_event, info)
165
166
  };
166
167
  }
167
168
  result[self.lower_camelize(key)] = method_ref.react_event_handler_function;
@@ -181,9 +182,9 @@ module React
181
182
  }
182
183
  } else if (key[0] === 'a' && key.startsWith("aria_")) {
183
184
  result[key.replace("_", "-")] = value;
184
- } else if (key === "style") {
185
+ } else if (key === "style" || key === "theme") {
185
186
  if (typeof value.$to_n === "function") { value = value.$to_n() }
186
- result["style"] = value;
187
+ result[key] = value;
187
188
  } else {
188
189
  result[self.lower_camelize(key)] = value;
189
190
  }
@@ -98,12 +98,13 @@ module React
98
98
  end
99
99
  alias gre get_react_element
100
100
 
101
- def method_ref(method_symbol)
101
+ def method_ref(method_symbol, *args)
102
+ method_key = "#{method_symbol}#{args}"
102
103
  %x{
103
- if (#@native.method_refs && #@native.method_refs[#{method_symbol}]) { return #@native.method_refs[#{method_symbol}]; }
104
+ if (#@native.method_refs && #@native.method_refs[#{method_key}]) { return #@native.method_refs[#{method_key}]; }
104
105
  if (!#@native.method_refs) { #@native.method_refs = {}; }
105
- #@native.method_refs[#{method_symbol}] = #{method(method_symbol)};
106
- return #@native.method_refs[#{method_symbol}];
106
+ #@native.method_refs[#{method_key}] = { m: #{method(method_symbol)}, a: args };
107
+ return #@native.method_refs[#{method_key}];
107
108
  }
108
109
  end
109
110
  alias m_ref method_ref
data/lib/react/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module React
2
- VERSION = '16.13.10'
2
+ VERSION = '16.13.11'
3
3
  end
@@ -0,0 +1,203 @@
1
+ module ReactNative
2
+ module Component
3
+ module Elements
4
+ # https://www.w3.org/TR/html52/fullindex.html#index-elements
5
+ # https://www.w3.org/TR/SVG11/eltindex.html
6
+ UNSUPPORTED_HTML_AND_SVG_ELEMENTS = %w[
7
+ a abbr address area article aside audio
8
+ base bdi bdo blockquote body br
9
+ canvas caption cite col colgroup
10
+ data datalist dd del details dfn dialog dl dt
11
+ em embed
12
+ fieldset figcaption figure footer form
13
+ head header hr html
14
+ iframe ins
15
+ kbd
16
+ label legend li link
17
+ main map mark meta meter
18
+ nav noscript
19
+ object ol optgroup option output
20
+ param picture progress
21
+ q
22
+ rp rt rtc ruby
23
+ s samp script section select small source span strong style sub summary sup
24
+ table tbody td template textarea tfoot th thead time title tr track
25
+ ul
26
+ var video
27
+ wbr
28
+
29
+ altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform
30
+ color-profile cursor
31
+ desc
32
+ feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting
33
+ feDisplacementMap feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur
34
+ feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting
35
+ feSpotLight feTile feTurbulence
36
+ filter font font-face font-face-format font-face-name font-face-src font-face-uri
37
+ glyph glyphRef
38
+ hkern
39
+ metadata missing-glyph mpath
40
+ script set style switch
41
+ tref
42
+ view vkern
43
+ ]
44
+
45
+ UNSUPPORTED_HTML_AND_SVG_ELEMENTS.each do |element|
46
+ define_method(element) do |*args, &block|
47
+ `console.warn("Element " + element + " is not yet supported, using a Text component as substitute!")`
48
+ `Opal.React.internal_prepare_args_and_render(Opal.global.Text, args, block)`
49
+ end
50
+ define_method(`element.toUpperCase()`) do |*args, &block|
51
+ `console.warn("Element " + element + " is not yet supported, using a Text component as substitute!")`
52
+ `Opal.React.internal_prepare_args_and_render(Opal.global.Text, args, block)`
53
+ end
54
+ end
55
+
56
+ # button
57
+ %x{
58
+ self['supported_button'] = function(props) {
59
+ let theme = Opal.global.React.useContext(Opal.global.ThemeContext);
60
+ let style = {};
61
+ if (theme && typeof theme['button'] !== 'undefined') { style = theme['button']; }
62
+ if (typeof props.style !== 'undefined') {
63
+ style = Opal.React.merge_deep(style, props.style);
64
+ }
65
+ let new_props = Object.assign({}, props, { style: style });
66
+ if (typeof props.title === 'undefined') {
67
+ try {
68
+ new_props.title = props.children.props.children;
69
+ } catch (e) {
70
+ console.error("BUTTON accepts only one string child!")
71
+ }
72
+ }
73
+ return Opal.global.React.createElement(Opal.global.Button, new_props);
74
+ }
75
+ self['supported_button'].displayName = 'BUTTON';
76
+ }
77
+ define_method('button') do |*args, &block|
78
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements.supported_button, args, block)`
79
+ end
80
+ define_method('BUTTON') do |*args, &block|
81
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements.supported_button, args, block)`
82
+ end
83
+
84
+ # img
85
+ define_method('img') do |*args, &block|
86
+ `Opal.React.internal_prepare_args_and_render(Opal.global.Image, args, block)`
87
+ end
88
+ define_method('IMG') do |*args, &block|
89
+ `Opal.React.internal_prepare_args_and_render(Opal.global.Image, args, block)`
90
+ end
91
+
92
+ # input
93
+ %x{
94
+ self.supported_input = function(props) {
95
+ Opal.React.render_buffer.push([]);
96
+ if (typeof props.type !== 'undefined') {
97
+ if (props.type === 'text') { return Opal.React.internal_prepare_args_and_render(Opal.global.TextInput, props); }
98
+ else if (props.type === 'checkbox') { return Opal.React.internal_prepare_args_and_render(Opal.global.InputSwitch, props); }
99
+ else {
100
+ console.warn("Input type " + props.type + " not supported. Using TextInput as substitute!");
101
+ return Opal.React.internal_prepare_args_and_render(Opal.global.TextInput, props);
102
+ }
103
+ }
104
+ Opal.React.internal_prepare_args_and_render(Opal.global.TextInput, props);
105
+ return Opal.React.render_buffer.pop();
106
+ }
107
+ }
108
+ define_method('input') do |*args, &block|
109
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements.supported_input, args, block)`
110
+ end
111
+ define_method('INPUT') do |*args, &block|
112
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements.supported_input, args, block)`
113
+ end
114
+
115
+ # elements that map to Text with style
116
+ SUPPORTED_TEXT_HTML_ELEMENTS = %w[
117
+ b
118
+ code
119
+ h1 h2 h3 h4 h5 h6
120
+ i
121
+ pre
122
+ span
123
+ u
124
+ ]
125
+
126
+ SUPPORTED_TEXT_HTML_ELEMENTS.each do |element|
127
+ fun_name = 'supported_' + element
128
+ %x{
129
+ self[fun_name] = function(props) {
130
+ let theme = Opal.global.React.useContext(Opal.global.ThemeContext);
131
+ let style = {};
132
+ if (theme && typeof theme[element] !== 'undefined') { style = theme[element]; }
133
+ if (typeof props.style !== 'undefined') {
134
+ style = Opal.React.merge_deep(style, props.style);
135
+ }
136
+ let new_props = Object.assign({}, props, { style: style });
137
+ return Opal.global.React.createElement(Opal.global.Text, new_props);
138
+ }
139
+ self[fun_name].displayName = element.toUpperCase();
140
+ }
141
+ define_method(`element.toLowerCase()`) do |*args, &block|
142
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements[fun_name], args, block)`
143
+ end
144
+ define_method(`element.toUpperCase()`) do |*args, &block|
145
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements[fun_name], args, block)`
146
+ end
147
+ end
148
+
149
+ SUPPORTED_VIEW_HTML_ELEMENTS = %w[
150
+ div
151
+ p
152
+ ]
153
+
154
+ SUPPORTED_VIEW_HTML_ELEMENTS.each do |element|
155
+ fun_name = 'supported_' + element
156
+ %x{
157
+ self[fun_name] = function(props) {
158
+ let theme = Opal.global.React.useContext(Opal.global.ThemeContext);
159
+ let style = {};
160
+ if (theme && typeof theme[element] !== 'undefined') { style = theme[element]; }
161
+ if (typeof props.style !== 'undefined') {
162
+ style = Opal.React.merge_deep(style, props.style);
163
+ }
164
+ let new_props = Object.assign({}, props, { style: style });
165
+ return Opal.global.React.createElement(Opal.global.View, new_props);
166
+ }
167
+ self[fun_name].displayName = element.toUpperCase();
168
+ }
169
+ define_method(`element.toLowerCase()`) do |*args, &block|
170
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements[fun_name], args, block)`
171
+ end
172
+ define_method(`element.toUpperCase()`) do |*args, &block|
173
+ `Opal.React.internal_prepare_args_and_render(Opal.ReactNative.Component.Elements[fun_name], args, block)`
174
+ end
175
+ end
176
+
177
+ SUPPORTED_SVG_ELEMENTS = %w[
178
+ Circle ClipPath
179
+ Defs
180
+ Ellipse
181
+ ForeignObject
182
+ G
183
+ Image
184
+ Line LinearGradient
185
+ Marker Mask
186
+ Path Pattern Polygon Polyline
187
+ RadialGradient Rect
188
+ Stop Svg Symbol
189
+ Text TextPath TSpan
190
+ Use
191
+ ]
192
+
193
+ SUPPORTED_SVG_ELEMENTS.each do |element|
194
+ define_method(`element.toLowerCase()`) do |*args, &block|
195
+ `Opal.React.internal_prepare_args_and_render(Opal.global.ReactNativeSvg[element], args, block)`
196
+ end
197
+ define_method(`element.toUpperCase()`) do |*args, &block|
198
+ `Opal.React.internal_prepare_args_and_render(Opal.global.ReactNativeSvg[element], args, block)`
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,51 @@
1
+ module LucidApp
2
+ module ReactNativeComponentConstructor
3
+ # for should_component_update we apply ruby semantics for comparing props
4
+ # to do so, we convert the props to ruby hashes and then compare
5
+ # this makes sure, that for example rubys Nil object gets handled properly
6
+ def self.extended(base)
7
+ component_name = base.to_s + 'Wrapper'
8
+ theme_component_name = base.to_s + 'ThemeWrapper'
9
+ # language=JS
10
+ %x{
11
+ base.jss_theme = {};
12
+ base.themed_react_component = function(props) {
13
+ const opag = Opal.global;
14
+ const theme = opag.React.useContext(opag.ThemeContext);
15
+ let classes;
16
+ if (base.jss_styles) {
17
+ if (!base.use_styles || (Opal.Isomorfeus.development === true)) {
18
+ let styles;
19
+ if (typeof base.jss_styles === 'function') { styles = base.jss_styles(theme); }
20
+ else { styles = base.jss_styles; }
21
+ base.use_styles = Opal.React.merge_deep(theme, opag.StyleSheet.create(styles));
22
+ }
23
+ classes = base.use_styles;
24
+ } else {
25
+ classes = theme;
26
+ }
27
+ let themed_classes_props = Object.assign({}, props, { classes: classes, theme: theme });
28
+ return opag.React.createElement(base.lucid_react_component, themed_classes_props);
29
+ };
30
+ base.themed_react_component.displayName = #{theme_component_name};
31
+ base.react_component = class extends Opal.global.React.Component {
32
+ constructor(props) {
33
+ super(props);
34
+ if (Opal.Isomorfeus.$top_component() == nil) { Opal.Isomorfeus['$top_component='](this); }
35
+ }
36
+ static get displayName() {
37
+ return "IsomorfeusTopLevelComponent";
38
+ }
39
+ static set displayName(new_name) {
40
+ // dont do anything here except returning the set value
41
+ return new_name;
42
+ }
43
+ render() {
44
+ let themed_component = Opal.global.React.createElement(base.themed_react_component, this.props);
45
+ return Opal.global.React.createElement(Opal.global.ThemeContext.Provider, { value: Opal.global.DefaultTheme }, themed_component);
46
+ }
47
+ }
48
+ }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ module LucidComponent
2
+ module ReactNativeComponentConstructor
3
+ # for should_component_update we apply ruby semantics for comparing props
4
+ # to do so, we convert the props to ruby hashes and then compare
5
+ # this makes sure, that for example rubys Nil object gets handled properly
6
+ def self.extended(base)
7
+ component_name = base.to_s + 'Wrapper'
8
+ # language=JS
9
+ %x{
10
+ base.react_component = Opal.global.React.memo(function(props) {
11
+ let opag = Opal.global;
12
+ let store;
13
+ if (base.store_updates) { store = opag.React.useContext(opag.LucidApplicationContext); }
14
+ const theme = opag.React.useContext(opag.ThemeContext);
15
+ let classes;
16
+ if (base.jss_styles) {
17
+ if (!base.use_styles || (Opal.Isomorfeus.development === true)) {
18
+ let styles;
19
+ if (typeof base.jss_styles === 'function') { styles = base.jss_styles(theme); }
20
+ else { styles = base.jss_styles; }
21
+ base.use_styles = Opal.React.merge_deep(theme, opag.StyleSheet.create(styles));
22
+ }
23
+ classes = base.use_styles;
24
+ } else {
25
+ classes = theme;
26
+ }
27
+ let new_props = Object.assign({}, props);
28
+ new_props.theme = theme;
29
+ new_props.classes = classes;
30
+ new_props.store = store;
31
+ return opag.React.createElement(base.lucid_react_component, new_props);
32
+ }, Opal.React.props_are_equal);
33
+ base.react_component.displayName = #{component_name};
34
+ }
35
+ end
36
+ end
37
+ end