isomorfeus-react 16.10.0 → 16.10.1
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.
- checksums.yaml +4 -4
- data/README.md +64 -0
- data/lib/browser/delegate_native.rb +70 -0
- data/lib/browser/element.rb +176 -0
- data/lib/browser/element/canvas.rb +17 -0
- data/lib/browser/element/media.rb +78 -0
- data/lib/browser/event.rb +92 -0
- data/lib/browser/event_target.rb +39 -0
- data/lib/browser/file_list.rb +125 -0
- data/lib/browser/iterable.rb +15 -0
- data/lib/isomorfeus-react-material-ui.rb +10 -0
- data/lib/isomorfeus-react.rb +145 -0
- data/lib/isomorfeus/config.rb +130 -0
- data/lib/isomorfeus/props/validate_hash_proxy.rb +178 -0
- data/lib/isomorfeus/props/validator.rb +131 -0
- data/lib/isomorfeus/react_view_helper.rb +130 -0
- data/lib/isomorfeus/top_level.rb +86 -0
- data/lib/isomorfeus/top_level_ssr.rb +28 -0
- data/lib/lucid_app/api.rb +30 -0
- data/lib/lucid_app/base.rb +7 -0
- data/lib/lucid_app/context.rb +7 -0
- data/lib/lucid_app/mixin.rb +20 -0
- data/lib/lucid_app/native_component_constructor.rb +105 -0
- data/lib/lucid_component/app_store_defaults.rb +36 -0
- data/lib/lucid_component/app_store_proxy.rb +38 -0
- data/lib/lucid_component/base.rb +7 -0
- data/lib/lucid_component/class_store_proxy.rb +41 -0
- data/lib/lucid_component/component_class_store_defaults.rb +38 -0
- data/lib/lucid_component/component_instance_store_defaults.rb +35 -0
- data/lib/lucid_component/event_handler.rb +17 -0
- data/lib/lucid_component/initializer.rb +12 -0
- data/lib/lucid_component/instance_store_proxy.rb +45 -0
- data/lib/lucid_component/mixin.rb +18 -0
- data/lib/lucid_component/native_component_constructor.rb +116 -0
- data/lib/lucid_component/reducers.rb +48 -0
- data/lib/lucid_component/store_api.rb +38 -0
- data/lib/lucid_component/styles_support.rb +37 -0
- data/lib/lucid_material/app/base.rb +9 -0
- data/lib/lucid_material/app/mixin.rb +22 -0
- data/lib/lucid_material/app/native_component_constructor.rb +107 -0
- data/lib/lucid_material/component/base.rb +9 -0
- data/lib/lucid_material/component/mixin.rb +20 -0
- data/lib/lucid_material/component/native_component_constructor.rb +118 -0
- data/lib/lucid_prop_declaration/mixin.rb +91 -0
- data/lib/react.rb +195 -0
- data/lib/react/active_support_support.rb +13 -0
- data/lib/react/children.rb +35 -0
- data/lib/react/component/api.rb +80 -0
- data/lib/react/component/base.rb +9 -0
- data/lib/react/component/callbacks.rb +106 -0
- data/lib/react/component/elements.rb +60 -0
- data/lib/react/component/event_handler.rb +19 -0
- data/lib/react/component/features.rb +47 -0
- data/lib/react/component/history.rb +36 -0
- data/lib/react/component/initializer.rb +11 -0
- data/lib/react/component/location.rb +15 -0
- data/lib/react/component/match.rb +31 -0
- data/lib/react/component/mixin.rb +19 -0
- data/lib/react/component/native_component_constructor.rb +93 -0
- data/lib/react/component/props.rb +59 -0
- data/lib/react/component/resolution.rb +70 -0
- data/lib/react/component/should_component_update.rb +14 -0
- data/lib/react/component/state.rb +52 -0
- data/lib/react/component/styles.rb +27 -0
- data/lib/react/component/unsafe_api.rb +33 -0
- data/lib/react/context_wrapper.rb +46 -0
- data/lib/react/function_component/api.rb +63 -0
- data/lib/react/function_component/base.rb +9 -0
- data/lib/react/function_component/creator.rb +32 -0
- data/lib/react/function_component/event_handler.rb +13 -0
- data/lib/react/function_component/mixin.rb +14 -0
- data/lib/react/function_component/resolution.rb +62 -0
- data/lib/react/memo_component/base.rb +9 -0
- data/lib/react/memo_component/creator.rb +32 -0
- data/lib/react/memo_component/mixin.rb +14 -0
- data/lib/react/native_constant_wrapper.rb +26 -0
- data/lib/react/pure_component/base.rb +9 -0
- data/lib/react/pure_component/mixin.rb +18 -0
- data/lib/react/ref.rb +13 -0
- data/lib/react/synthetic_event.rb +53 -0
- data/lib/react/version.rb +3 -0
- data/lib/react_dom.rb +47 -0
- data/lib/react_dom_server.rb +19 -0
- metadata +84 -2
@@ -0,0 +1,28 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
class TopLevel
|
3
|
+
class << self
|
4
|
+
attr_accessor :ssr_route_path
|
5
|
+
attr_accessor :transport_ws_url
|
6
|
+
|
7
|
+
def mount!
|
8
|
+
# nothing, but keep it for compatibility with browser
|
9
|
+
end
|
10
|
+
|
11
|
+
def render_component_to_string(component_name, props)
|
12
|
+
component = nil
|
13
|
+
%x{
|
14
|
+
if (typeof component_name === 'string' || component_name instanceof String) {
|
15
|
+
component = component_name.split(".").reduce(function(o, x) {
|
16
|
+
return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
|
17
|
+
}, Opal.global)
|
18
|
+
} else {
|
19
|
+
component = component_name;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
component = Isomorfeus.cached_component_class(component_name) unless component
|
23
|
+
|
24
|
+
ReactDOMServer.render_to_string(React.create_element(component, `Opal.Hash.$new(props)`))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module LucidApp
|
2
|
+
module API
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_exec do
|
5
|
+
def theme(theme_hash = nil, &block)
|
6
|
+
if block_given?
|
7
|
+
%x{
|
8
|
+
let result = block.$call(Opal.Hash.$new(base.jss_theme));
|
9
|
+
if (typeof result.$to_n === 'function') { base.jss_theme = result.$to_n(); }
|
10
|
+
else { base.jss_theme = result; }
|
11
|
+
return result;
|
12
|
+
}
|
13
|
+
elsif theme_hash
|
14
|
+
`base.jss_theme = #{theme_hash.to_n}` if theme_hash
|
15
|
+
theme_hash
|
16
|
+
elsif `typeof base.jss_theme === 'object'`
|
17
|
+
`Opal.Hash.$new(base.jss_theme)`
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
alias_method :theme=, :theme
|
23
|
+
end
|
24
|
+
|
25
|
+
def context
|
26
|
+
@native.JS[:context]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module LucidApp
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
base.include(::Native::Wrapper)
|
5
|
+
base.extend(::LucidApp::NativeComponentConstructor)
|
6
|
+
base.extend(::LucidPropDeclaration::Mixin)
|
7
|
+
base.extend(::React::Component::ShouldComponentUpdate)
|
8
|
+
base.extend(::LucidComponent::EventHandler)
|
9
|
+
base.include(::React::Component::Elements)
|
10
|
+
base.include(::React::Component::API)
|
11
|
+
base.include(::React::Component::Callbacks)
|
12
|
+
base.include(::LucidComponent::StoreAPI)
|
13
|
+
base.include(::LucidComponent::StylesSupport)
|
14
|
+
base.include(::LucidApp::API)
|
15
|
+
base.include(::LucidComponent::Initializer)
|
16
|
+
base.include(::React::Component::Features)
|
17
|
+
base.include(::React::Component::Resolution)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module LucidApp
|
2
|
+
module NativeComponentConstructor
|
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
|
8
|
+
# language=JS
|
9
|
+
%x{
|
10
|
+
base.lucid_react_component = class extends Opal.global.React.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.state.isomorfeus_store_state = Opal.Isomorfeus.store.native.getState();
|
19
|
+
var current_store_state = this.state.isomorfeus_store_state;
|
20
|
+
if (typeof current_store_state.component_class_state[#{component_name}] !== "undefined") {
|
21
|
+
this.state.component_class_state = {};
|
22
|
+
this.state.component_class_state[#{component_name}] = current_store_state.component_class_state[#{component_name}];
|
23
|
+
} else {
|
24
|
+
this.state.component_class_state = {};
|
25
|
+
this.state.component_class_state[#{component_name}] = {};
|
26
|
+
};
|
27
|
+
this.__ruby_instance = base.$new(this);
|
28
|
+
this.__object_id = this.__ruby_instance.$object_id().$to_s();
|
29
|
+
if (Opal.Isomorfeus.$top_component() == nil) { Opal.Isomorfeus['$top_component='](this); }
|
30
|
+
if (!this.state.component_state) {
|
31
|
+
this.state.component_state = {};
|
32
|
+
this.state.component_state[this.__object_id] = {};
|
33
|
+
};
|
34
|
+
var event_handlers = #{base.event_handlers};
|
35
|
+
for (var i = 0; i < event_handlers.length; i++) {
|
36
|
+
this[event_handlers[i]] = this[event_handlers[i]].bind(this);
|
37
|
+
}
|
38
|
+
var defined_refs = #{base.defined_refs};
|
39
|
+
for (var ref in defined_refs) {
|
40
|
+
if (defined_refs[ref] != null) {
|
41
|
+
this[ref] = function(element) {
|
42
|
+
element = Opal.React.native_element_or_component_to_ruby(element);
|
43
|
+
#{`this.__ruby_instance`.instance_exec(`element`, &`defined_refs[ref]`)}
|
44
|
+
}
|
45
|
+
this[ref] = this[ref].bind(this);
|
46
|
+
} else {
|
47
|
+
this[ref] = Opal.global.React.createRef();
|
48
|
+
}
|
49
|
+
}
|
50
|
+
this.listener = this.listener.bind(this);
|
51
|
+
this.unsubscriber = Opal.Isomorfeus.store.native.subscribe(this.listener);
|
52
|
+
}
|
53
|
+
static get displayName() {
|
54
|
+
return #{component_name};
|
55
|
+
}
|
56
|
+
render() {
|
57
|
+
Opal.React.render_buffer.push([]);
|
58
|
+
Opal.React.active_components.push(this);
|
59
|
+
Opal.React.active_redux_components.push(this.__ruby_instance);
|
60
|
+
#{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
|
61
|
+
Opal.React.active_redux_components.pop();
|
62
|
+
Opal.React.active_components.pop();
|
63
|
+
let children = Opal.React.render_buffer.pop();
|
64
|
+
return Opal.global.React.createElement(Opal.global.LucidApplicationContext.Provider, { value: this.state.isomorfeus_store_state }, children);
|
65
|
+
}
|
66
|
+
listener() {
|
67
|
+
let next_state = Opal.Isomorfeus.store.native.getState();
|
68
|
+
this.setState({ isomorfeus_store_state: next_state });
|
69
|
+
}
|
70
|
+
componentWillUnmount() {
|
71
|
+
if (typeof this.unsubscriber === "function") { this.unsubscriber(); };
|
72
|
+
}
|
73
|
+
validateProp(props, propName, componentName) {
|
74
|
+
try { base.$validate_prop(propName, props[propName]) }
|
75
|
+
catch (e) { return new Error(componentName + ": Error: prop validation failed: " + e.message); }
|
76
|
+
return null;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
base.jss_styles = null;
|
80
|
+
base.jss_styles_used = null;
|
81
|
+
base.jss_theme = {};
|
82
|
+
base.use_styles = null;
|
83
|
+
base.themed_react_component = function(props) {
|
84
|
+
let classes = null;
|
85
|
+
let theme = Opal.global.ReactJSS.useTheme();
|
86
|
+
if (base.jss_styles) {
|
87
|
+
if (!base.use_styles || (Opal.Isomorfeus["$development?"]() && !Object.is(base.jss_styles, base.jss_styles_used))) {
|
88
|
+
base.jss_styles_used = base.jss_styles;
|
89
|
+
let styles = base.jss_styles
|
90
|
+
if (typeof styles === 'function') { styles = styles(theme); }
|
91
|
+
base.use_styles = Opal.global.ReactJSS.createUseStyles(styles);
|
92
|
+
}
|
93
|
+
classes = base.use_styles();
|
94
|
+
}
|
95
|
+
let themed_classes_props = Object.assign({}, props, { classes: classes, theme: theme });
|
96
|
+
return Opal.global.React.createElement(base.lucid_react_component, themed_classes_props);
|
97
|
+
}
|
98
|
+
base.react_component = function(props) {
|
99
|
+
let themed_component = Opal.global.React.createElement(base.themed_react_component, props);
|
100
|
+
return Opal.global.React.createElement(Opal.global.ReactJSS.ThemeProvider, { theme: base.jss_theme }, themed_component);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class AppStoreDefaults
|
3
|
+
def initialize(state, component_name)
|
4
|
+
@state = state
|
5
|
+
if @state.isomorfeus_store
|
6
|
+
@state.isomorfeus_store.merge!(application_state: {})
|
7
|
+
else
|
8
|
+
@state.isomorfeus_store = { application_state: {}}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(key, *args, &block)
|
13
|
+
if `args.length > 0`
|
14
|
+
# set initial class state
|
15
|
+
key = key.chop if `key.endsWith('=')`
|
16
|
+
@state.isomorfeus_store[:application_state][key] = args[0]
|
17
|
+
current_state = Isomorfeus.store.get_state
|
18
|
+
if !(current_state[:application_state].key?(key))
|
19
|
+
Isomorfeus.store.dispatch(type: 'APPLICATION_STATE', name: key, value: args[0])
|
20
|
+
end
|
21
|
+
else
|
22
|
+
# get class state
|
23
|
+
|
24
|
+
# check if we have a component local state value
|
25
|
+
if @state.isomorfeus_store[:application_state].key?(key)
|
26
|
+
return @state.isomorfeus_store[:application_state][key]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_h
|
33
|
+
@state.isomorfeus_store[:application_state]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class AppStoreProxy
|
3
|
+
def initialize(component_instance)
|
4
|
+
@native_component_instance = component_instance.to_n
|
5
|
+
@component_instance = component_instance
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(key, *args, &block)
|
9
|
+
if `args.length > 0`
|
10
|
+
# set class state, simply a dispatch
|
11
|
+
action = { type: 'APPLICATION_STATE', name: (`key.endsWith('=')` ? key.chop : key), value: args[0] }
|
12
|
+
Isomorfeus.store.dispatch(action)
|
13
|
+
else
|
14
|
+
# check if we have a component local state value
|
15
|
+
if `this.native_component_instance.context.application_state.hasOwnProperty(key)`
|
16
|
+
return @native_component_instance.JS['context'].JS[:application_state].JS[key]
|
17
|
+
elsif @component_instance.class.default_app_store_defined && @component_instance.class.app_store.to_h.key?(key)
|
18
|
+
# check if a default value was given
|
19
|
+
return @component_instance.class.app_store.to_h[key]
|
20
|
+
end
|
21
|
+
# otherwise return nil
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def dispatch(action)
|
27
|
+
Isomorfeus.store.dispatch(action)
|
28
|
+
end
|
29
|
+
|
30
|
+
def subscribe(&block)
|
31
|
+
Isomorfeus.store.subscribe(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def unsubscribe(unsubscriber)
|
35
|
+
`unsubscriber()`
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class ClassStoreProxy
|
3
|
+
def initialize(component_instance)
|
4
|
+
@native_component_instance = component_instance.to_n
|
5
|
+
@component_instance = component_instance
|
6
|
+
@component_name = component_instance.class.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(key, *args, &block)
|
10
|
+
if `args.length > 0`
|
11
|
+
# set class state, simply a dispatch
|
12
|
+
action = { type: 'COMPONENT_CLASS_STATE', class: @component_name, name: (`key.endsWith('=')` ? key.chop : key), value: args[0] }
|
13
|
+
Isomorfeus.store.dispatch(action)
|
14
|
+
else
|
15
|
+
# get class state
|
16
|
+
# check if we have a component local state value
|
17
|
+
if @native_component_instance.JS['context'].JS[:component_class_state].JS[@component_name] &&
|
18
|
+
@native_component_instance.JS['context'].JS[:component_class_state].JS[@component_name].JS.hasOwnProperty(key)
|
19
|
+
return @native_component_instance.JS['context'].JS[:component_class_state].JS[@component_name].JS[key]
|
20
|
+
elsif @component_instance.class.default_class_store_defined && @component_instance.class.class_store.to_h.key?(key)
|
21
|
+
# check if a default value was given
|
22
|
+
return @component_instance.class.class_store.to_h[key]
|
23
|
+
end
|
24
|
+
# otherwise return nil
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def dispatch(action)
|
30
|
+
Isomorfeus.store.dispatch(action)
|
31
|
+
end
|
32
|
+
|
33
|
+
def subscribe(&block)
|
34
|
+
Isomorfeus.store.subscribe(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def unsubscribe(unsubscriber)
|
38
|
+
`unsubscriber()`
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class ComponentClassStoreDefaults
|
3
|
+
def initialize(state, component_name)
|
4
|
+
@state = state
|
5
|
+
@component_name = component_name
|
6
|
+
if @state.isomorfeus_store
|
7
|
+
@state.isomorfeus_store.merge!(component_class_state: { @component_name => {} })
|
8
|
+
else
|
9
|
+
@state.isomorfeus_store = { component_class_state: { @component_name => {} } }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(key, *args, &block)
|
14
|
+
if `args.length > 0`
|
15
|
+
# set initial class state
|
16
|
+
key = key.chop if `key.endsWith('=')`
|
17
|
+
@state.isomorfeus_store[:component_class_state][@component_name][key] = args[0]
|
18
|
+
current_state = Isomorfeus.store.get_state
|
19
|
+
if !(current_state[:component_class_state].key?(@component_name) && current_state[:component_class_state][@component_name].key?(key))
|
20
|
+
Isomorfeus.store.dispatch(type: 'COMPONENT_CLASS_STATE', class: @component_name, name: key, value: args[0])
|
21
|
+
end
|
22
|
+
else
|
23
|
+
# get class state
|
24
|
+
|
25
|
+
# check if we have a component local state value
|
26
|
+
|
27
|
+
if @state.isomorfeus_store[:component_class_state][@component_name].key?(key)
|
28
|
+
return @state.isomorfeus_store[:component_class_state][@component_name][key]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_h
|
35
|
+
@state.isomorfeus_store[:component_class_state][@component_name]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class ComponentInstanceStoreDefaults
|
3
|
+
def initialize(state, component_name)
|
4
|
+
@state = {}
|
5
|
+
@component_name = component_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(key, *args, &block)
|
9
|
+
if `args.length > 0`
|
10
|
+
# set initial class state
|
11
|
+
key = key.chop if `key.endsWith('=')`
|
12
|
+
@state[key] = args[0]
|
13
|
+
current_state = Isomorfeus.store.get_state
|
14
|
+
if !(current_state[:component_state].key?(@component_name) &&
|
15
|
+
current_state[:component_state][@component_name].key?(:instance_defaults) &&
|
16
|
+
current_state[:component_state][@component_name][:instance_defaults].key?(key))
|
17
|
+
Isomorfeus.store.dispatch(type: 'COMPONENT_CLASS_STATE', class: @component_name, name: :instance_defaults, value: { key => args[0]})
|
18
|
+
end
|
19
|
+
else
|
20
|
+
# get class state
|
21
|
+
|
22
|
+
# check if we have a component local state value
|
23
|
+
|
24
|
+
if @state.key?(key)
|
25
|
+
return @state[key]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_h
|
32
|
+
@state
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module EventHandler
|
3
|
+
def event_handlers
|
4
|
+
@event_handlers ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def event_handler(name, &block)
|
8
|
+
event_handlers << name
|
9
|
+
%x{
|
10
|
+
self.lucid_react_component.prototype[name] = function(event, info) {
|
11
|
+
#{ruby_event = ::React::SyntheticEvent.new(`event`)};
|
12
|
+
#{`this.__ruby_instance`.instance_exec(ruby_event, `info`, &block)};
|
13
|
+
}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module Initializer
|
3
|
+
def initialize(native_component)
|
4
|
+
@native = native_component
|
5
|
+
@app_store = `Opal.LucidComponent.AppStoreProxy.$new(#{self})`
|
6
|
+
@class_store = `Opal.LucidComponent.ClassStoreProxy.$new(#{self})`
|
7
|
+
@props = `Opal.React.Component.Props.$new(#@native)`
|
8
|
+
@state = `Opal.React.Component.State.$new(#@native)`
|
9
|
+
@store = `Opal.LucidComponent.InstanceStoreProxy.$new(#{self})`
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
class InstanceStoreProxy
|
3
|
+
def initialize(component_instance)
|
4
|
+
@native_component_instance = component_instance.to_n
|
5
|
+
@component_instance = component_instance
|
6
|
+
@component_object_id = component_instance.object_id.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(key, *args, &block)
|
10
|
+
if `args.length > 0`
|
11
|
+
# set instance state, simply a dispatch
|
12
|
+
|
13
|
+
action = { type: 'COMPONENT_STATE', object_id: @component_object_id, name: (`key.endsWith('=')` ? key.chop : key), value: args[0] }
|
14
|
+
Isomorfeus.store.dispatch(action)
|
15
|
+
|
16
|
+
else
|
17
|
+
# get instance state
|
18
|
+
|
19
|
+
if @native_component_instance.JS[:context].JS[:component_state].JS[@component_object_id] &&
|
20
|
+
@native_component_instance.JS[:context].JS[:component_state].JS[@component_object_id].JS.hasOwnProperty(key)
|
21
|
+
# check if we have a component local state value
|
22
|
+
return @native_component_instance.JS[:context].JS[:component_state].JS[@component_object_id].JS[key]
|
23
|
+
elsif @component_instance.class.default_instance_store_defined && @component_instance.class.store.to_h.key?(key)
|
24
|
+
# check if a default value was given
|
25
|
+
return @component_instance.class.store.to_h[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
# otherwise return nil
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def dispatch(action)
|
34
|
+
Isomorfeus.store.dispatch(action)
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscribe(&block)
|
38
|
+
Isomorfeus.store.subscribe(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def unsubscribe(unsubscriber)
|
42
|
+
`unsubscriber()`
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|