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,124 @@
1
+ module Preact
2
+ module Component
3
+ module Api
4
+ def self.included(base)
5
+ base.instance_exec do
6
+ base_module = base.to_s.deconstantize
7
+ if base_module != ''
8
+ base_module.constantize.define_singleton_method(base.to_s.demodulize) do |*args, &block|
9
+ `Opal.Preact.internal_prepare_args_and_render(#{base}.preact_component, args, block)`
10
+ end
11
+ else
12
+ Object.define_method(base.to_s) do |*args, &block|
13
+ `Opal.Preact.internal_prepare_args_and_render(#{base}.preact_component, args, block)`
14
+ end
15
+ end
16
+
17
+ attr_accessor :props
18
+ attr_accessor :state
19
+
20
+ def ref(ref_name, &block)
21
+ defined_refs.JS[ref_name] = block_given? ? block : `null`
22
+ end
23
+
24
+ def defined_refs
25
+ @defined_ref ||= `{}`
26
+ end
27
+
28
+ def default_state_defined
29
+ @default_state_defined
30
+ end
31
+
32
+ def state
33
+ return @default_state if @default_state
34
+ @default_state_defined = true
35
+ %x{
36
+ var native_state = {state: {}};
37
+ native_state.setState = function(new_state, callback) {
38
+ for (var key in new_state) {
39
+ this.state[key] = new_state[key];
40
+ }
41
+ if (callback) { callback.call(); }
42
+ }
43
+ }
44
+ @default_state = Preact::Component::State.new(`native_state`)
45
+ end
46
+
47
+ def render(&block)
48
+ `base.render_block = #{block}`
49
+ end
50
+
51
+ def should_component_update?(&block)
52
+ `base.should_component_update_block = block`
53
+ end
54
+ end
55
+ end
56
+
57
+ def display_name
58
+ @native.JS[:displayName]
59
+ end
60
+
61
+ def force_update(&block)
62
+ if block_given?
63
+ # this maybe needs instance_exec too
64
+ @native.JS.forceUpdate(`function() { block.$call(); }`)
65
+ else
66
+ @native.JS.forceUpdate
67
+ end
68
+ end
69
+
70
+ def get_preact_element(arg, &block)
71
+ if block_given?
72
+ # execute block, fetch last element from buffer
73
+ %x{
74
+ let last_buffer_length = Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1].length;
75
+ let last_buffer_element = Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1][last_buffer_length - 1];
76
+ block.$call();
77
+ // console.log("get_preact_element popping", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString())
78
+ let new_element = Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1].pop();
79
+ if (last_buffer_element === new_element) { #{Isomorfeus.raise_error(message: "Block did not create any Preact element!")} }
80
+ return new_element;
81
+ }
82
+ else
83
+ # element was rendered before being passed as arg
84
+ # fetch last element from buffer
85
+ # `console.log("get_preact_element popping", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString())`
86
+ `Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1].pop()`
87
+ end
88
+ end
89
+ alias gpe get_preact_element
90
+
91
+ def method_ref(method_symbol, *args)
92
+ method_key = "#{method_symbol}#{args}"
93
+ %x{
94
+ if (#@native.method_refs && #@native.method_refs[#{method_key}]) { return #@native.method_refs[#{method_key}]; }
95
+ if (!#@native.method_refs) { #@native.method_refs = {}; }
96
+ #@native.method_refs[#{method_key}] = { m: #{method(method_symbol)}, a: args };
97
+ return #@native.method_refs[#{method_key}];
98
+ }
99
+ end
100
+ alias m_ref method_ref
101
+
102
+ def render_preact_element(el)
103
+ # push el to buffer
104
+ `Opal.Preact.render_buffer[Opal.Preact.render_buffer.length - 1].push(el)`
105
+ # `console.log("render_preact_element pushed", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString())`
106
+ nil
107
+ end
108
+ alias rpe render_preact_element
109
+
110
+ def ref(name)
111
+ `#@native[name]`
112
+ end
113
+
114
+ def ruby_ref(name)
115
+ return `#@native[name]` if `(typeof #@native[name] === 'function')`
116
+ Preact::Ref::new(`#@native[name]`)
117
+ end
118
+
119
+ def set_state(updater, &callback)
120
+ @state.set_state(updater, &callback)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,9 @@
1
+ module Preact
2
+ module Component
3
+ class Base
4
+ def self.inherited(base)
5
+ base.include(::Preact::Component::Mixin)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,102 @@
1
+ module Preact
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
8
+ %x{
9
+ var fun = function(error) {
10
+ Opal.Preact.active_redux_components.push(this);
11
+ #{`this.__ruby_instance`.instance_exec(`error`, &block)};
12
+ Opal.Preact.active_redux_components.pop();
13
+ }
14
+ if (self.lucid_preact_component) { self.lucid_preact_component.prototype.componentDidCatch = fun; }
15
+ else { self.preact_component.prototype.componentDidCatch = fun; }
16
+ }
17
+ end
18
+
19
+ def component_did_mount(&block)
20
+ %x{
21
+ let fun = function() {
22
+ Opal.Preact.active_redux_components.push(this);
23
+ #{`this.__ruby_instance`.instance_exec(&block)};
24
+ Opal.Preact.active_redux_components.pop();
25
+ }
26
+ if (self.lucid_preact_component) {
27
+ if (self.lucid_preact_component.prototype.componentDidMount) {
28
+ let fun_one = self.lucid_preact_component.prototype.componentDidMount;
29
+ let fun_two = fun;
30
+ fun = function() {
31
+ fun_one();
32
+ fun_two();
33
+ }
34
+ }
35
+ self.lucid_preact_component.prototype.componentDidMount = fun;
36
+ } else { self.preact_component.prototype.componentDidMount = fun; }
37
+ }
38
+ end
39
+
40
+ def component_did_update(&block)
41
+ %x{
42
+ var fun = function(prev_props, prev_state, snapshot) {
43
+ Opal.Preact.active_redux_components.push(this);
44
+ #{`this.__ruby_instance`.instance_exec(`Opal.Preact.Component.Props.$new({props: prev_props})`,
45
+ `Opal.Preact.Component.State.$new({state: prev_state})`,
46
+ `snapshot`, &block)};
47
+ Opal.Preact.active_redux_components.pop();
48
+ }
49
+ if (self.lucid_preact_component) { self.lucid_preact_component.prototype.componentDidUpdate = fun; }
50
+ else { self.preact_component.prototype.componentDidUpdate = fun; }
51
+ }
52
+ end
53
+
54
+ def component_will_unmount(&block)
55
+ %x{
56
+ var fun = function() {
57
+ if (typeof this.unsubscriber === "function") { this.unsubscriber(); };
58
+ Opal.Preact.active_redux_components.push(this);
59
+ #{`this.__ruby_instance`.instance_exec(&block)};
60
+ Opal.Preact.active_redux_components.pop();
61
+ }
62
+ if (self.lucid_preact_component) { self.lucid_preact_component.prototype.componentWillUnmount = fun; }
63
+ else { self.preact_component.prototype.componentWillUnmount = fun; }
64
+ }
65
+ end
66
+
67
+
68
+ def get_derived_state_from_props(&block)
69
+ %x{
70
+ var fun = function(props, state) {
71
+ Opal.Preact.active_redux_components.push(this);
72
+ var result = #{`this.__ruby_instance`.instance_exec(`Opal.Preact.Component.Props.$new({props: props})`,
73
+ `Opal.Preact.Component.State.$new({state: state})`, &block)};
74
+ Opal.Preact.active_redux_components.pop();
75
+ if (typeof result.$to_n === 'function') { result = result.$to_n() }
76
+ if (result === Opal.nil) { return null; }
77
+ return result;
78
+ }
79
+ if (self.lucid_preact_component) { self.lucid_preact_component.prototype.getDerivedStateFromProps = fun; }
80
+ else { self.preact_component.prototype.getDerivedStateFromProps = fun; }
81
+ }
82
+ end
83
+
84
+ def get_snapshot_before_update(&block)
85
+ %x{
86
+ var fun = function(prev_props, prev_state) {
87
+ Opal.Preact.active_redux_components.push(this);
88
+ var result = #{`this.__ruby_instance`.instance_exec(`Opal.Preact.Component.Props.$new({props: prev_props})`,
89
+ `Opal.Preact.Component.State.$new({state: prev_state})`, &block)};
90
+ Opal.Preact.active_redux_components.pop();
91
+ if (result === Opal.nil) { return null; }
92
+ return result;
93
+ }
94
+ if (self.lucid_preact_component) { self.lucid_preact_component.prototype.getSnapshotBeforeUpdate = fun; }
95
+ else { self.preact_component.prototype.getSnapshotBeforeUpdate = fun; }
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,64 @@
1
+ module Preact
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
+ SUPPORTED_HTML_AND_SVG_ELEMENTS = %w[
7
+ a abbr address area article aside audio
8
+ b base bdi bdo blockquote body br button
9
+ canvas caption cite code col colgroup
10
+ data datalist dd del details dfn dialog div dl dt
11
+ em embed
12
+ fieldset figcaption figure footer form
13
+ h1 h2 h3 h4 h5 h6 head header hr html
14
+ i iframe img input ins
15
+ kbd
16
+ label legend li link
17
+ main map mark meta meter
18
+ nav noscript
19
+ object ol optgroup option output
20
+ p param picture pre 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
+ u ul
26
+ var video
27
+ wbr
28
+ altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform
29
+ circle clipPath color-profile cursor
30
+ defs desc
31
+ ellipse
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 foreignObject
37
+ g glyph glyphRef
38
+ hkern
39
+ image
40
+ line linearGradient
41
+ marker mask metadata missing-glyph mpath
42
+ path pattern polygon polyline
43
+ radialGradient rect
44
+ script set stop style svg switch symbol
45
+ text textPath tref tspan
46
+ use
47
+ view vkern
48
+ ]
49
+
50
+ SUPPORTED_HTML_AND_SVG_ELEMENTS.each do |element|
51
+ define_method(element) do |*args, &block|
52
+ `Opal.Preact.internal_prepare_args_and_render(element, args, block)`
53
+ end
54
+ define_method(`element.toUpperCase()`) do |*args, &block|
55
+ `Opal.Preact.internal_prepare_args_and_render(element, args, block)`
56
+ end
57
+ end
58
+
59
+ def Fragment(*args, &block)
60
+ `Opal.Preact.internal_prepare_args_and_render(Opal.global.Preact.Fragment, args, block)`
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,11 @@
1
+ module Preact
2
+ module Component
3
+ module Initializer
4
+ def initialize(native_component)
5
+ @native = native_component
6
+ @props = `Opal.Preact.Component.Props.$new(#@native)`
7
+ @state = `Opal.Preact.Component.State.$new(#@native)`
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Preact
2
+ module Component
3
+ module Mixin
4
+ def self.included(base)
5
+ base.include(::Native::Wrapper)
6
+ base.extend(::Preact::Component::NativeComponentConstructor)
7
+ base.extend(::LucidPropDeclaration::Mixin)
8
+ base.include(::Preact::Component::Elements)
9
+ base.include(::Preact::Component::Api)
10
+ base.include(::Preact::Component::Callbacks)
11
+ base.include(::Preact::Component::Initializer)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,65 @@
1
+ module Preact
2
+ module Component
3
+ module NativeComponentConstructor
4
+ # for should_component_update we apply ruby semantics for comparing props
5
+ # to do so, we convert the props to ruby hashes and then compare
6
+ # this makes sure, that for example rubys Nil object gets handled properly
7
+ def self.extended(base)
8
+ component_name = base.to_s
9
+ %x{
10
+ base.preact_component = class extends Opal.global.Preact.Component {
11
+ constructor(props) {
12
+ super(props);
13
+ if (base.$default_state_defined()) {
14
+ this.state = base.$state().$to_n();
15
+ } else {
16
+ this.state = {};
17
+ };
18
+ this.__ruby_instance = base.$new(this);
19
+ var defined_refs = #{base.defined_refs};
20
+ for (var ref in defined_refs) {
21
+ if (defined_refs[ref] != null) {
22
+ this[ref] = function(element) {
23
+ element = Opal.Preact.native_element_or_component_to_ruby(element);
24
+ #{`this.__ruby_instance`.instance_exec(`element`, &`defined_refs[ref]`)}
25
+ }
26
+ this[ref] = this[ref].bind(this);
27
+ } else {
28
+ this[ref] = Opal.global.Preact.createRef();
29
+ }
30
+ }
31
+ }
32
+ static get displayName() {
33
+ return #{component_name};
34
+ }
35
+ render(props, state) {
36
+ const oper = Opal.Preact;
37
+ oper.render_buffer.push([]);
38
+ // console.log("react component pushed", oper.render_buffer, oper.render_buffer.toString());
39
+ oper.active_components.push(this);
40
+ let block_result = #{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
41
+ if (block_result && block_result !== nil) { oper.render_block_result(block_result); }
42
+ // console.log("react component popping", oper.render_buffer, oper.render_buffer.toString());
43
+ oper.active_components.pop();
44
+ let result = oper.render_buffer.pop();
45
+ return (result.length === 1) ? result[0] : result;
46
+ }
47
+ shouldComponentUpdate(next_props, next_state) {
48
+ if (base.should_component_update_block) {
49
+ return #{!!`this.__ruby_instance`.instance_exec(Preact::Component::Props.new(`{props: next_props}`), Preact::Component::State.new(`{state: next_state }`), &`base.should_component_update_block`)};
50
+ }
51
+ if (!Opal.Preact.props_are_equal(this.props, next_props)) { return true; }
52
+ if (Opal.Preact.state_is_not_equal(this.state, next_state)) { return true; }
53
+ return false;
54
+ }
55
+ validateProp(props, propName, componentName) {
56
+ try { base.$validate_prop(propName, props[propName]) }
57
+ catch (e) { return new Error(componentName + " Error: prop validation failed: " + e.message); }
58
+ return null;
59
+ }
60
+ }
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ module Preact
2
+ module Component
3
+ class Params
4
+ include Native::Wrapper
5
+
6
+ def method_missing(prop, *args, &block)
7
+ %x{
8
+ const p = #@native;
9
+ if (typeof p[prop] === 'undefined') {
10
+ prop = Opal.Preact.lower_camelize(prop);
11
+ if (typeof p[prop] === 'undefined') { return nil; }
12
+ }
13
+ return p[prop];
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,55 @@
1
+ module Preact
2
+ module Component
3
+ class Props
4
+ def initialize(native)
5
+ @native = native
6
+ end
7
+
8
+ def method_missing(prop, *args, &block)
9
+ %x{
10
+ const p = #@native.props;
11
+ if (typeof p[prop] === 'undefined') {
12
+ prop = Opal.Preact.lower_camelize(prop);
13
+ if (typeof p[prop] === 'undefined') { return nil; }
14
+ }
15
+ return p[prop];
16
+ }
17
+ end
18
+
19
+ def children
20
+ @native.JS[:props].JS[:children]
21
+ end
22
+
23
+ def isomorfeus_store
24
+ # TODO
25
+ @native.JS[:props].JS[:isomorfeus_store]
26
+ end
27
+
28
+ def theme
29
+ `#@native.props.iso_theme`
30
+ end
31
+
32
+ def params
33
+ return @params if @params
34
+ return nil if `typeof #@native.props.params === 'undefined'`
35
+ @params = ::Preact::Component::Params.new(`#@native.props.params`)
36
+ end
37
+
38
+ def to_h
39
+ `Opal.Hash.$new(#@native.props)`.transform_keys!(&:underscore)
40
+ end
41
+
42
+ def to_json
43
+ JSON.dump(to_transport)
44
+ end
45
+
46
+ def to_n
47
+ @native.JS[:props]
48
+ end
49
+
50
+ def to_transport
51
+ {}.merge(to_h)
52
+ end
53
+ end
54
+ end
55
+ end