isomorfeus-preact 10.5.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 (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