isomorfeus-preact 10.5.0

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/README.md +62 -0
  3. data/lib/browser/delegate_native.rb +70 -0
  4. data/lib/browser/element.rb +176 -0
  5. data/lib/browser/element/canvas.rb +17 -0
  6. data/lib/browser/element/media.rb +78 -0
  7. data/lib/browser/event.rb +92 -0
  8. data/lib/browser/event_target.rb +39 -0
  9. data/lib/browser/file_list.rb +125 -0
  10. data/lib/browser/iterable.rb +15 -0
  11. data/lib/isomorfeus-preact.rb +109 -0
  12. data/lib/isomorfeus/preact/config.rb +189 -0
  13. data/lib/isomorfeus/preact/memcached_component_cache.rb +19 -0
  14. data/lib/isomorfeus/preact/redis_component_cache.rb +19 -0
  15. data/lib/isomorfeus/preact/thread_local_component_cache.rb +17 -0
  16. data/lib/isomorfeus/preact_view_helper.rb +188 -0
  17. data/lib/isomorfeus/props/validate_hash_proxy.rb +186 -0
  18. data/lib/isomorfeus/props/validator.rb +159 -0
  19. data/lib/isomorfeus/top_level.rb +101 -0
  20. data/lib/isomorfeus/top_level_ssr.rb +27 -0
  21. data/lib/isomorfeus_preact/lucid_app/api.rb +22 -0
  22. data/lib/isomorfeus_preact/lucid_app/base.rb +7 -0
  23. data/lib/isomorfeus_preact/lucid_app/mixin.rb +16 -0
  24. data/lib/isomorfeus_preact/lucid_app/native_component_constructor.rb +91 -0
  25. data/lib/isomorfeus_preact/lucid_component/api.rb +68 -0
  26. data/lib/isomorfeus_preact/lucid_component/app_store_proxy.rb +37 -0
  27. data/lib/isomorfeus_preact/lucid_component/base.rb +7 -0
  28. data/lib/isomorfeus_preact/lucid_component/class_store_proxy.rb +44 -0
  29. data/lib/isomorfeus_preact/lucid_component/initializer.rb +14 -0
  30. data/lib/isomorfeus_preact/lucid_component/instance_store_proxy.rb +44 -0
  31. data/lib/isomorfeus_preact/lucid_component/mixin.rb +15 -0
  32. data/lib/isomorfeus_preact/lucid_component/native_component_constructor.rb +84 -0
  33. data/lib/isomorfeus_preact/lucid_component/styles_api.rb +31 -0
  34. data/lib/isomorfeus_preact/lucid_component/styles_wrapper.rb +40 -0
  35. data/lib/isomorfeus_preact/lucid_func/base.rb +7 -0
  36. data/lib/isomorfeus_preact/lucid_func/initializer.rb +11 -0
  37. data/lib/isomorfeus_preact/lucid_func/mixin.rb +12 -0
  38. data/lib/isomorfeus_preact/lucid_func/native_component_constructor.rb +55 -0
  39. data/lib/isomorfeus_preact/preact/function_component/api.rb +123 -0
  40. data/lib/isomorfeus_preact/preact/function_component/base.rb +9 -0
  41. data/lib/isomorfeus_preact/preact/function_component/initializer.rb +10 -0
  42. data/lib/isomorfeus_preact/preact/function_component/mixin.rb +12 -0
  43. data/lib/isomorfeus_preact/preact/function_component/native_component_constructor.rb +48 -0
  44. data/lib/lucid_app/context.rb +24 -0
  45. data/lib/lucid_prop_declaration/mixin.rb +126 -0
  46. data/lib/preact.rb +309 -0
  47. data/lib/preact/component/api.rb +124 -0
  48. data/lib/preact/component/base.rb +9 -0
  49. data/lib/preact/component/callbacks.rb +102 -0
  50. data/lib/preact/component/elements.rb +64 -0
  51. data/lib/preact/component/initializer.rb +11 -0
  52. data/lib/preact/component/mixin.rb +15 -0
  53. data/lib/preact/component/native_component_constructor.rb +65 -0
  54. data/lib/preact/component/params.rb +18 -0
  55. data/lib/preact/component/props.rb +55 -0
  56. data/lib/preact/component/resolution.rb +97 -0
  57. data/lib/preact/component/state.rb +58 -0
  58. data/lib/preact/context_wrapper.rb +46 -0
  59. data/lib/preact/native_constant_wrapper.rb +29 -0
  60. data/lib/preact/options.rb +98 -0
  61. data/lib/preact/ref.rb +17 -0
  62. data/lib/preact/version.rb +3 -0
  63. metadata +301 -0
@@ -0,0 +1,10 @@
1
+ module Preact
2
+ module FunctionComponent
3
+ module Initializer
4
+ def initialize
5
+ self.JS[:native_props] = `{ props: null }`
6
+ @native_props = ::Preact::Component::Props.new(self)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Preact
2
+ module FunctionComponent
3
+ module Mixin
4
+ def self.included(base)
5
+ base.include(::Preact::Component::Elements)
6
+ base.include(::Preact::FunctionComponent::Initializer)
7
+ base.include(::Preact::FunctionComponent::Api)
8
+ base.extend(::Preact::FunctionComponent::NativeComponentConstructor)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,48 @@
1
+ module Preact
2
+ module FunctionComponent
3
+ module NativeComponentConstructor
4
+ def self.extended(base)
5
+ component_name = base.to_s
6
+ %x{
7
+ base.instance_init = function(initial) {
8
+ let ruby_state = { instance: #{base.new(`{}`)} };
9
+ ruby_state.instance.__ruby_instance = ruby_state.instance;
10
+ return ruby_state;
11
+ }
12
+ base.instance_reducer = function(state, action) { return state; }
13
+ base.preact_component = function(props) {
14
+ const oper = Opal.Preact;
15
+ oper.render_buffer.push([]);
16
+ // console.log("function pushed", oper.render_buffer, oper.render_buffer.toString());
17
+ const [__ruby_state, __ruby_dispatch] = Opal.global.PreactHooks.useReducer(base.instance_reducer, null, base.instance_init);
18
+ const __ruby_instance = __ruby_state.instance;
19
+ __ruby_instance.props = props;
20
+ oper.active_components.push(__ruby_instance);
21
+ let block_result = #{`__ruby_instance`.instance_exec(&`base.render_block`)};
22
+ if (block_result && block_result !== nil) { oper.render_block_result(block_result); }
23
+ oper.active_components.pop();
24
+ // console.log("function popping", oper.render_buffer, oper.render_buffer.toString());
25
+ let result = oper.render_buffer.pop();
26
+ return (result.length === 1) ? result[0] : result;
27
+ }
28
+ base.preact_component.displayName = #{component_name};
29
+ }
30
+
31
+ base_module = base.to_s.deconstantize
32
+ if base_module != ''
33
+ base_module.constantize.define_singleton_method(base.to_s.demodulize) do |*args, &block|
34
+ `Opal.Preact.internal_prepare_args_and_render(#{base}.preact_component, args, block)`
35
+ end
36
+ else
37
+ Object.define_method(base.to_s) do |*args, &block|
38
+ `Opal.Preact.internal_prepare_args_and_render(#{base}.preact_component, args, block)`
39
+ end
40
+ end
41
+
42
+ def render(&block)
43
+ `base.render_block = #{block}`
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ module LucidApp
2
+ module Context
3
+ def self.create_application_context
4
+ nano_css = `null`
5
+ css_server = `null`
6
+ css_server = `document.getElementById('css-server-side')` unless on_ssr?
7
+ %x{
8
+ let og = Opal.global;
9
+ nano_css = (css_server) ? og.NanoCSS.create({ sh: css_server }) : og.NanoCSS.create();
10
+ og.NanoCSSAddOns.rule(nano_css);
11
+ og.NanoCSSAddOns.sheet(nano_css);
12
+ og.NanoCSSAddOns.nesting(nano_css);
13
+ og.NanoCSSAddOns.hydrate(nano_css);
14
+ og.NanoCSSAddOns.unitless(nano_css);
15
+ og.NanoCSSAddOns.global(nano_css);
16
+ og.NanoCSSAddOns.keyframes(nano_css);
17
+ og.NanoCSSAddOns.fade_in(nano_css);
18
+ og.NanoCSSAddOns.fade_out(nano_css);
19
+ og.NanoCSSInstance = nano_css;
20
+ }
21
+ Preact.create_context('LucidApplicationContext', { iso_store: Isomorfeus.store, nano_css: nano_css })
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,126 @@
1
+ module LucidPropDeclaration
2
+ module Mixin
3
+ if RUBY_ENGINE == 'opal'
4
+ def self.extended(base)
5
+ def prop(prop_name, validate_hash = { required: true })
6
+ validate_hash = validate_hash.to_h if validate_hash.class == Isomorfeus::Props::ValidateHashProxy
7
+ if validate_hash.key?(:default)
8
+ %x{
9
+ if (base.lucid_preact_component) {
10
+ let preact_prop_name = Opal.Preact.lower_camelize(prop_name);
11
+ #{value = validate_hash[:default]}
12
+ if (!base.lucid_preact_component.defaultProps) { base.lucid_preact_component.defaultProps = {}; }
13
+ base.lucid_preact_component.defaultProps[preact_prop_name] = value;
14
+ if (!base.lucid_preact_component.propTypes) { base.lucid_preact_component.propTypes = {}; }
15
+ base.lucid_preact_component.propTypes[preact_prop_name] = base.lucid_preact_component.prototype.validateProp;
16
+ } else if (base.preact_component) {
17
+ let preact_prop_name = Opal.Preact.lower_camelize(prop_name);
18
+ #{value = validate_hash[:default]}
19
+ if (!base.preact_component.defaultProps) { base.preact_component.defaultProps = {}; }
20
+ base.preact_component.defaultProps[preact_prop_name] = value;
21
+ if (!base.preact_component.propTypes) { base.preact_component.propTypes = {}; }
22
+ base.preact_component.propTypes[preact_prop_name] = base.preact_component.prototype.validateProp;
23
+ }
24
+ }
25
+ end
26
+ declared_props[prop_name.to_sym] = validate_hash
27
+ end
28
+ end
29
+
30
+ def validate_function
31
+ %x{
32
+ if (typeof self.validate_function === 'undefined') {
33
+ self.validate_function = function(props_object) {
34
+ try { self.$validate_props(Opal.Hash.$new(props_object)) }
35
+ catch (e) { return e.message; }
36
+ }
37
+ }
38
+ return self.validate_function;
39
+ }
40
+ end
41
+
42
+ def validate_prop_function(prop)
43
+ function_name = "validate_#{prop}_function"
44
+ %x{
45
+ if (typeof self[function_name] === 'undefined') {
46
+ self[function_name] = function(value) {
47
+ try { self.$validate_prop(prop, value); }
48
+ catch (e) { return e.message; }
49
+ }
50
+ }
51
+ return self[function_name];
52
+ }
53
+ end
54
+ else
55
+ def prop(prop_name, validate_hash = { required: true })
56
+ validate_hash = validate_hash.to_h if validate_hash.class == Isomorfeus::Props::ValidateHashProxy
57
+ declared_props[prop_name.to_sym] = validate_hash
58
+ end
59
+ end
60
+
61
+ def declared_props
62
+ @declared_props ||= {}
63
+ end
64
+
65
+ def valid_prop?(prop, value)
66
+ validate_prop(prop, value)
67
+ rescue
68
+ false
69
+ end
70
+
71
+ def valid_props?(props)
72
+ validate_props(props)
73
+ rescue
74
+ false
75
+ end
76
+
77
+ def validate
78
+ Isomorfeus::Props::ValidateHashProxy.new
79
+ end
80
+
81
+ def validate_prop(prop, value)
82
+ return false unless declared_props.key?(prop)
83
+ validator = Isomorfeus::Props::Validator.new(self, prop, value, declared_props[prop])
84
+ validator.validate!
85
+ true
86
+ end
87
+
88
+ def validate_props(props)
89
+ props = {} unless props
90
+ declared_props.each_key do |prop|
91
+ if declared_props[prop].key?(:required) && declared_props[prop][:required] && !props.key?(prop)
92
+ Isomorfeus.raise_error(message: "Required prop #{prop} not given!")
93
+ end
94
+ end
95
+ result = true
96
+ props.each do |p, v|
97
+ r = validate_prop(p, v)
98
+ result = false unless r
99
+ end
100
+ result
101
+ end
102
+
103
+ def validated_prop(prop, value)
104
+ Isomorfeus.raise_error(message: "No such prop #{prop} declared!") unless declared_props.key?(prop)
105
+ validator = Isomorfeus::Props::Validator.new(self, prop, value, declared_props[prop])
106
+ validator.validated_value
107
+ end
108
+
109
+ def validated_props(props)
110
+ props = {} unless props
111
+
112
+ declared_props.each_key do |prop|
113
+ if declared_props[prop].key?(:required) && declared_props[prop][:required] && !props.key?(prop)
114
+ Isomorfeus.raise_error(message: "Required prop #{prop} not given!")
115
+ end
116
+ props[prop] = nil unless props.key?(prop) # let validator handle value
117
+ end
118
+
119
+ result = {}
120
+ props.each do |p, v|
121
+ result[p] = validated_prop(p, v)
122
+ end
123
+ result
124
+ end
125
+ end
126
+ end
data/lib/preact.rb ADDED
@@ -0,0 +1,309 @@
1
+ module Preact
2
+ %x{
3
+ self.render_buffer = [];
4
+
5
+ self.set_validate_prop = function(component, prop_name) {
6
+ let core = component.preact_component;
7
+ if (typeof core.propTypes == "undefined") {
8
+ core.propTypes = {};
9
+ core.propValidations = {};
10
+ core.propValidations[prop_name] = {};
11
+ }
12
+ core.propTypes[prop_name] = core.prototype.validateProp;
13
+ };
14
+
15
+ self.props_are_equal = function(this_props, next_props) {
16
+ let counter = 0;
17
+ for (var property in next_props) {
18
+ counter++;
19
+ if (next_props.hasOwnProperty(property)) {
20
+ if (!this_props.hasOwnProperty(property)) { return false; };
21
+ if (property === "children") { if (next_props.children !== this_props.children) { return false; }}
22
+ else if (typeof next_props[property] === "object" && next_props[property] !== null && typeof next_props[property]['$!='] === "function" &&
23
+ typeof this_props[property] !== "undefined" && this_props[property] !== null ) {
24
+ if (#{ !! (`next_props[property]` != `this_props[property]`) }) { return false; }
25
+ } else if (next_props[property] !== this_props[property]) { return false; }
26
+ }
27
+ }
28
+ if (counter !== Object.keys(this_props).length) { return false; }
29
+ return true;
30
+ };
31
+
32
+ self.state_is_not_equal = function(this_state, next_state) {
33
+ let counter = 0;
34
+ for (var property in next_state) {
35
+ counter++;
36
+ if (next_state.hasOwnProperty(property)) {
37
+ if (!this_state.hasOwnProperty(property)) { return true; };
38
+ if (typeof next_state[property] === "object" && next_state[property] !== null && typeof next_state[property]['$!='] === "function" &&
39
+ typeof this_state[property] !== "undefined" && this_state[property] !== null) {
40
+ if (#{ !! (`next_state[property]` != `this_state[property]`) }) { return true }
41
+ } else if (next_state[property] !== this_state[property]) { return true }
42
+ }
43
+ }
44
+ if (counter !== Object.keys(this_state).length) { return true; }
45
+ return false;
46
+ };
47
+
48
+ self.lower_camelize = function(snake_cased_word) {
49
+ if (self.prop_dictionary[snake_cased_word]) { return self.prop_dictionary[snake_cased_word]; }
50
+ let parts = snake_cased_word.split('_');
51
+ let res = parts[0];
52
+ for (let i = 1; i < parts.length; i++) {
53
+ res += parts[i][0].toUpperCase() + parts[i].slice(1);
54
+ }
55
+ self.prop_dictionary[snake_cased_word] = res;
56
+ return res;
57
+ };
58
+
59
+ self.native_element_or_component_to_ruby = function (element) {
60
+ if (typeof element.__ruby_instance !== 'undefined') { return element.__ruby_instance }
61
+ if (element instanceof Element || element instanceof Node) { return #{Browser::Element.new(`element`)} }
62
+ return element;
63
+ };
64
+
65
+ self.native_to_ruby_event = function(event) {
66
+ if (event.hasOwnProperty('target')) { return #{::Browser::Event.new(`event`)}; }
67
+ else if (Array.isArray(event)) { return event; }
68
+ else { return Opal.Hash.$new(event); }
69
+ };
70
+
71
+ self.internal_prepare_args_and_render = function(component, args, block) {
72
+ const operain = self.internal_render;
73
+ if (args.length > 0) {
74
+ let last_arg = args[args.length - 1];
75
+ if (last_arg && last_arg.constructor === String) {
76
+ if (args.length === 1) { return operain(component, null, last_arg, null); }
77
+ else { operain(component, args[0], last_arg, null); }
78
+ } else { operain(component, args[0], null, block); }
79
+ } else { operain(component, null, null, block); }
80
+ };
81
+
82
+ self.active_components = [];
83
+
84
+ self.active_component = function() {
85
+ let length = self.active_components.length;
86
+ if (length === 0) { return null; };
87
+ return self.active_components[length-1];
88
+ };
89
+
90
+ self.active_redux_components = [];
91
+
92
+ self.active_redux_component = function() {
93
+ let length = self.active_redux_components.length;
94
+ if (length === 0) { return null; };
95
+ return self.active_redux_components[length-1];
96
+ };
97
+
98
+ function isObject(obj) { return (obj && typeof obj === 'object'); }
99
+
100
+ self.merge_deep = function(one, two) {
101
+ return [one, two].reduce(function(pre, obj) {
102
+ Object.keys(obj).forEach(function(key){
103
+ let pVal = pre[key];
104
+ let oVal = obj[key];
105
+ if (Array.isArray(pVal) && Array.isArray(oVal)) {
106
+ pre[key] = pVal.concat.apply(this, oVal);
107
+ } else if (isObject(pVal) && isObject(oVal)) {
108
+ pre[key] = self.merge_deep(pVal, oVal);
109
+ } else {
110
+ pre[key] = oVal;
111
+ }
112
+ });
113
+ return pre;
114
+ }, {});
115
+ };
116
+
117
+ self.prop_dictionary = {};
118
+
119
+ self.to_native_preact_props = function(ruby_style_props) {
120
+ let result = {};
121
+ let keys = ruby_style_props.$$keys;
122
+ let keys_length = keys.length;
123
+ let key = '';
124
+ for (let i = 0; i < keys_length; i++) {
125
+ key = keys[i];
126
+ let value = ruby_style_props.$$smap[key];
127
+ if (key[0] === 'o' && key[1] === 'n' && key[2] === '_') {
128
+ let type = typeof value;
129
+ if (type === "function") {
130
+ let active_c = self.active_component();
131
+ result[self.lower_camelize(key)] = function(event, info) {
132
+ let ruby_event = self.native_to_ruby_event(event);
133
+ #{`active_c.__ruby_instance`.instance_exec(`ruby_event`, `info`, &`value`)};
134
+ }
135
+ } else if (type === "object" && typeof value.m === "object" && typeof value.m.$call === "function" ) {
136
+ if (!value.preact_event_handler_function) {
137
+ value.preact_event_handler_function = function(event, info) {
138
+ let ruby_event = self.native_to_ruby_event(event);
139
+ if (value.a.length > 0) { value.m.$call.apply(value.m, [ruby_event, info].concat(value.a)); }
140
+ else { value.m.$call(ruby_event, info); }
141
+ };
142
+ }
143
+ result[self.lower_camelize(key)] = value.preact_event_handler_function;
144
+ } else if (type === "string" ) {
145
+ let active_component = self.active_component();
146
+ let method_ref;
147
+ let method_name = '$' + value;
148
+ if (typeof active_component[method_name] === "function") {
149
+ // got a ruby instance
150
+ if (active_component.native && active_component.native.method_refs && active_component.native.method_refs[value]) { method_ref = active_component.native.method_refs[value]; } // ruby instance with native
151
+ else if (active_component.method_refs && active_component.method_refs[value]) { method_ref = active_component.method_refs[value]; } // ruby function component
152
+ else { method_ref = active_component.$method_ref(value); } // create the ref
153
+ } else if (typeof active_component.__ruby_instance[method_name] === "function") {
154
+ // got a native instance
155
+ if (active_component.method_refs && active_component.method_refs[value]) { method_ref = active_component.method_refs[value]; }
156
+ else { method_ref = active_component.__ruby_instance.$method_ref(value); } // create ref for native
157
+ }
158
+ if (method_ref) {
159
+ if (!method_ref.preact_event_handler_function) {
160
+ method_ref.preact_event_handler_function = function(event, info) {
161
+ let ruby_event = self.native_to_ruby_event(event);
162
+ method_ref.m.$call(ruby_event, info)
163
+ };
164
+ }
165
+ result[self.lower_camelize(key)] = method_ref.preact_event_handler_function;
166
+ } else {
167
+ let component_name;
168
+ if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
169
+ else { component_name = active_component.$to_s(); }
170
+ #{Isomorfeus.raise_error(message: "Is #{`value`} a valid method of #{`component_name`}? If so then please use: #{`key`}: method_ref(:#{`value`}) within component: #{`component_name`}")}
171
+ }
172
+ } else {
173
+ let active_component = self.active_component();
174
+ let component_name;
175
+ if (active_component.__ruby_instance) { component_name = active_component.__ruby_instance.$to_s(); }
176
+ else { component_name = active_component.$to_s(); }
177
+ #{Isomorfeus.raise_error(message: "Received invalid value for #{`key`} with #{`value`} within component: #{`component_name`}")}
178
+ console.error( + key + " event handler:", value, " within component:", self.active_component());
179
+ }
180
+ } else if (key[0] === 'a' && key.startsWith("aria_")) {
181
+ result[key.replace("_", "-")] = value;
182
+ } else if (key === "style" || key === "theme") {
183
+ if (typeof value.$to_n === "function") { value = value.$to_n() }
184
+ result[key] = value;
185
+ } else {
186
+ result[self.lower_camelize(key)] = value;
187
+ }
188
+ }
189
+ return result;
190
+ };
191
+
192
+ self.render_block_result = function(block_result) {
193
+ if (block_result.constructor === String || block_result.constructor === Number) {
194
+ Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1].push(block_result);
195
+ }
196
+ };
197
+
198
+ self.internal_render = function(component, props, string_child, block) {
199
+ const operabu = self.render_buffer;
200
+ let native_props;
201
+ if (props && props !== nil) { native_props = self.to_native_preact_props(props); }
202
+ if (string_child) {
203
+ operabu[operabu.length - 1].push(Opal.global.Preact.createElement(component, native_props, string_child));
204
+ } else if (block && block !== nil) {
205
+ operabu.push([]);
206
+ // console.log("internal_render pushed", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
207
+ let block_result = block.$call();
208
+ if (block_result && block_result !== nil) { Opal.Preact.render_block_result(block_result); }
209
+ // console.log("internal_render popping", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
210
+ let children = operabu.pop();
211
+ operabu[operabu.length - 1].push(Opal.global.Preact.createElement.apply(this, [component, native_props].concat(children)));
212
+ } else {
213
+ operabu[operabu.length - 1].push(Opal.global.Preact.createElement(component, native_props));
214
+ }
215
+ };
216
+ }
217
+
218
+
219
+ def self.create_element(type, props = nil, children = nil, &block)
220
+ %x{
221
+ const operabu = self.render_buffer;
222
+ let component = null;
223
+ let native_props = null;
224
+ if (typeof type.preact_component !== 'undefined') { component = type.preact_component; }
225
+ else { component = type; }
226
+ if (block !== nil) {
227
+ operabu.push([]);
228
+ // console.log("create_element pushed", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
229
+ let block_result = block.$call();
230
+ if (block_result && block_result !== nil) { Opal.Preact.render_block_result(block_result); }
231
+ // console.log("create_element popping", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
232
+ children = operabu.pop();
233
+ } else if (children === nil) { children = []; }
234
+ else if (typeof children === 'string') { children = [children]; }
235
+ if (props && props !== nil) { native_props = self.to_native_preact_props(props); }
236
+ return Opal.global.Preact.createElement.apply(this, [component, native_props].concat(children));
237
+ }
238
+ end
239
+
240
+ def self.to_child_array(props_children)
241
+ `Opal.global.Preact.toChildArray(children)`
242
+ end
243
+
244
+ def self.clone_element(ruby_preact_element, props = nil, children = nil, &block)
245
+ block_result = `null`
246
+ if block_given?
247
+ block_result = block.call
248
+ block_result = `null` unless block_result
249
+ end
250
+ native_props = props ? `Opal.Preact.to_native_preact_props(props)` : `null`
251
+ `Opal.global.Preact.cloneElement(ruby_preact_element.$to_n(), native_props, block_result)`
252
+ end
253
+
254
+ def self.create_context(const_name, default_value)
255
+ %x{
256
+ Opal.global[const_name] = Opal.global.Preact.createContext(default_value);
257
+ var new_const = #{Preact::ContextWrapper.new(`Opal.global[const_name]`)};
258
+ #{Object.const_set(const_name, `new_const`)};
259
+ return new_const;
260
+ }
261
+ end
262
+
263
+ def self.create_ref
264
+ Preact::Ref.new(`Opal.global.Preact.createRef()`)
265
+ end
266
+
267
+ def self.hydrate(native_preact_element, container_node, replace_node, &block)
268
+ # container is a native DOM element
269
+ if block_given?
270
+ `Opal.global.Preact.hydrate(native_preact_element, container_node, function() { block.$call() })`
271
+ else
272
+ `Opal.global.Preact.hydrate(native_preact_element, container_node)`
273
+ end
274
+ end
275
+
276
+ def self.location_hook(location)
277
+ %x{
278
+ if (Opal.global.locationHook) { return Opal.global.locationHook; }
279
+ else if (Opal.global.staticLocationHook) { return Opal.global.staticLocationHook(location); }
280
+ else { #{raise "Wouter Location Hooks not imported!"}; }
281
+ }
282
+ end
283
+
284
+ def self.render(native_preact_element, container_node, replace_node)
285
+ # container is a native DOM element
286
+ if block_given?
287
+ `Opal.global.Preact.render(native_preact_element, container_node, function() { block.$call() })`
288
+ else
289
+ `Opal.global.Preact.render(native_preact_element, container_node)`
290
+ end
291
+ end
292
+
293
+ if on_ssr?
294
+ def self.render_to_string(native_preact_element)
295
+ `Opal.global.Preact.renderToString(native_preact_element)`
296
+ end
297
+ end
298
+
299
+ def self.unmount_component_at_node(element_or_query)
300
+ if `(typeof element_or_query === 'string')` || (`(typeof element_or_query.$class === 'function')` && element_or_query.class == String)
301
+ element = `document.body.querySelector(element_or_query)`
302
+ elsif `(typeof element_or_query.$is_a === 'function')` && element_or_query.is_a?(Browser::Element)
303
+ element = element_or_query.to_n
304
+ else
305
+ element = element_or_query
306
+ end
307
+ `Opal.global.Preact.render(null, element)`
308
+ end
309
+ end