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,18 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
base.include(::Native::Wrapper)
|
5
|
+
base.extend(::LucidComponent::NativeComponentConstructor)
|
6
|
+
base.extend(::LucidPropDeclaration::Mixin)
|
7
|
+
base.extend(::LucidComponent::EventHandler)
|
8
|
+
base.include(::React::Component::Elements)
|
9
|
+
base.include(::React::Component::API)
|
10
|
+
base.include(::React::Component::Callbacks)
|
11
|
+
base.include(::LucidComponent::StoreAPI)
|
12
|
+
base.include(::LucidComponent::StylesSupport)
|
13
|
+
base.include(::LucidComponent::Initializer)
|
14
|
+
base.include(::React::Component::Features)
|
15
|
+
base.include(::React::Component::Resolution)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module LucidComponent
|
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.__ruby_instance = base.$new(this);
|
19
|
+
this.__object_id = this.__ruby_instance.$object_id().$to_s();
|
20
|
+
if (!this.state.component_state) {
|
21
|
+
this.state.component_state = {};
|
22
|
+
this.state.component_state[this.__object_id] = {};
|
23
|
+
};
|
24
|
+
var event_handlers = #{base.event_handlers};
|
25
|
+
for (var i = 0; i < event_handlers.length; i++) {
|
26
|
+
this[event_handlers[i]] = this[event_handlers[i]].bind(this);
|
27
|
+
}
|
28
|
+
var defined_refs = #{base.defined_refs};
|
29
|
+
for (var ref in defined_refs) {
|
30
|
+
if (defined_refs[ref] != null) {
|
31
|
+
this[ref] = function(element) {
|
32
|
+
element = Opal.React.native_element_or_component_to_ruby(element);
|
33
|
+
#{`this.__ruby_instance`.instance_exec(`element`, &`defined_refs[ref]`)}
|
34
|
+
}
|
35
|
+
this[ref] = this[ref].bind(this);
|
36
|
+
} else {
|
37
|
+
this[ref] = Opal.global.React.createRef();
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
static get displayName() {
|
42
|
+
return #{component_name};
|
43
|
+
}
|
44
|
+
render() {
|
45
|
+
Opal.React.render_buffer.push([]);
|
46
|
+
Opal.React.active_components.push(this);
|
47
|
+
Opal.React.active_redux_components.push(this);
|
48
|
+
#{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
|
49
|
+
Opal.React.active_redux_components.pop();
|
50
|
+
Opal.React.active_components.pop();
|
51
|
+
return Opal.React.render_buffer.pop();
|
52
|
+
}
|
53
|
+
data_access() {
|
54
|
+
return this.context;
|
55
|
+
}
|
56
|
+
shouldComponentUpdate(next_props, next_state) {
|
57
|
+
var next_props_keys = Object.keys(next_props);
|
58
|
+
var this_props_keys = Object.keys(this.props);
|
59
|
+
if (next_props_keys.length !== this_props_keys.length) { return true; }
|
60
|
+
|
61
|
+
var next_state_keys = Object.keys(next_state);
|
62
|
+
var this_state_keys = Object.keys(this.state);
|
63
|
+
if (next_state_keys.length !== this_state_keys.length) { return true; }
|
64
|
+
|
65
|
+
for (var property in next_props) {
|
66
|
+
if (next_props.hasOwnProperty(property)) {
|
67
|
+
if (!this.props.hasOwnProperty(property)) { return true; };
|
68
|
+
if (property == "children") { if (next_props.children !== this.props.children) { return true; }}
|
69
|
+
else if (typeof next_props[property] !== "undefined" && next_props[property] !== null &&
|
70
|
+
typeof next_props[property]['$!='] !== "undefined" &&
|
71
|
+
typeof this.props[property] !== "undefined" && this.props[property] !== null &&
|
72
|
+
typeof this.props[property]['$!='] !== "undefined") {
|
73
|
+
if (#{ !! (`next_props[property]` != `this.props[property]`) }) { return true; };
|
74
|
+
} else if (next_props[property] !== this.props[property]) { return true; };
|
75
|
+
}
|
76
|
+
}
|
77
|
+
for (var property in next_state) {
|
78
|
+
if (next_state.hasOwnProperty(property)) {
|
79
|
+
if (!this.state.hasOwnProperty(property)) { return true; };
|
80
|
+
if (next_state[property] !== null && typeof next_state[property]['$!='] !== "undefined" &&
|
81
|
+
this.state[property] !== null && typeof this.state[property]['$!='] !== "undefined") {
|
82
|
+
if (#{ !! (`next_state[property]` != `this.state[property]`) }) { return true };
|
83
|
+
} else if (next_state[property] !== this.state[property]) { return true };
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return false;
|
87
|
+
}
|
88
|
+
validateProp(props, propName, componentName) {
|
89
|
+
try { base.$validate_prop(propName, props[propName]) }
|
90
|
+
catch (e) { return new Error(componentName + " Error: prop validation failed: " + e.message); }
|
91
|
+
return null;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
base.lucid_react_component.contextType = Opal.global.LucidApplicationContext;
|
95
|
+
base.jss_styles = null;
|
96
|
+
base.jss_styles_used = null;
|
97
|
+
base.use_styles = null;
|
98
|
+
base.react_component = function(props) {
|
99
|
+
let classes = null;
|
100
|
+
let theme = Opal.global.ReactJSS.useTheme();
|
101
|
+
if (base.jss_styles) {
|
102
|
+
if (!base.use_styles || (Opal.Isomorfeus["$development?"]() && !Object.is(base.jss_styles, base.jss_styles_used))) {
|
103
|
+
base.jss_styles_used = base.jss_styles;
|
104
|
+
let styles = base.jss_styles
|
105
|
+
if (typeof styles === 'function') { styles = base.jss_styles(theme); }
|
106
|
+
base.use_styles = Opal.global.ReactJSS.createUseStyles(styles);
|
107
|
+
}
|
108
|
+
classes = base.use_styles();
|
109
|
+
}
|
110
|
+
let class_theme_props = Object.assign({}, props, { classes: classes, theme: theme });
|
111
|
+
return Opal.global.React.createElement(base.lucid_react_component, class_theme_props);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module Reducers
|
3
|
+
class << self
|
4
|
+
attr_reader :component_reducers_added
|
5
|
+
|
6
|
+
def add_component_reducers_to_store
|
7
|
+
unless component_reducers_added
|
8
|
+
@_component_reducers_added = true
|
9
|
+
component_reducer = Redux.create_reducer do |prev_state, action|
|
10
|
+
case action[:type]
|
11
|
+
when 'COMPONENT_STATE'
|
12
|
+
if action.key?(:set_state)
|
13
|
+
action[:set_state]
|
14
|
+
else
|
15
|
+
new_state = {}.merge!(prev_state) # make a copy of state
|
16
|
+
new_state[action[:object_id]] = {} unless new_state.key?(action[:object_id])
|
17
|
+
new_state[action[:object_id]].merge!(action[:name] => action[:value])
|
18
|
+
# new_state == prev_state ? prev_state : new_state
|
19
|
+
new_state
|
20
|
+
end
|
21
|
+
else
|
22
|
+
prev_state
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
component_class_reducer = Redux.create_reducer do |prev_state, action|
|
27
|
+
case action[:type]
|
28
|
+
when 'COMPONENT_CLASS_STATE'
|
29
|
+
if action.key?(:set_state)
|
30
|
+
action[:set_state]
|
31
|
+
else
|
32
|
+
new_state = {}.merge!(prev_state) # make a copy of state
|
33
|
+
new_state[action[:class]] = {} unless new_state.key?(action[:class])
|
34
|
+
new_state[action[:class]].merge!(action[:name] => action[:value])
|
35
|
+
# new_state == prev_state ? prev_state : new_state
|
36
|
+
new_state
|
37
|
+
end
|
38
|
+
else
|
39
|
+
prev_state
|
40
|
+
end
|
41
|
+
end
|
42
|
+
Redux::Store.preloaded_state_merge!(component_state: {}, component_class_state: {})
|
43
|
+
Redux::Store.add_reducers(component_state: component_reducer, component_class_state: component_class_reducer)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module StoreAPI
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_exec do
|
5
|
+
attr_accessor :app_store
|
6
|
+
attr_accessor :class_store
|
7
|
+
attr_accessor :store
|
8
|
+
|
9
|
+
def default_app_store_defined
|
10
|
+
@default_app_store_defined
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_class_store_defined
|
14
|
+
@default_class_store_defined
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_instance_store_defined
|
18
|
+
@default_instance_store_defined
|
19
|
+
end
|
20
|
+
|
21
|
+
def app_store
|
22
|
+
@default_app_store_defined = true
|
23
|
+
@default_app_store ||= ::LucidComponent::AppStoreDefaults.new(state, self.to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def class_store
|
27
|
+
@default_class_store_defined = true
|
28
|
+
@default_class_store ||= ::LucidComponent::ComponentClassStoreDefaults.new(state, self.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def store
|
32
|
+
@default_instance_store_defined = true
|
33
|
+
@default_instance_store ||= ::LucidComponent::ComponentInstanceStoreDefaults.new(state, self.to_s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module LucidComponent
|
2
|
+
module StylesSupport
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_exec do
|
5
|
+
def styles(styles_hash = nil, &block)
|
6
|
+
if block_given?
|
7
|
+
%x{
|
8
|
+
base.jss_styles = function(theme) {
|
9
|
+
let wrapped_theme = Opal.React.Component.Styles.$new(theme);
|
10
|
+
var result = block.$call(wrapped_theme);
|
11
|
+
return result.$to_n();
|
12
|
+
}
|
13
|
+
}
|
14
|
+
nil
|
15
|
+
elsif styles_hash
|
16
|
+
`base.jss_styles = #{styles_hash.to_n}` if styles_hash
|
17
|
+
styles_hash
|
18
|
+
elsif `typeof base.jss_styles === 'object'`
|
19
|
+
`Opal.Hash.$new(base.jss_styles)`
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
alias_method :styles=, :styles
|
25
|
+
end
|
26
|
+
|
27
|
+
def styles
|
28
|
+
props.classes
|
29
|
+
end
|
30
|
+
|
31
|
+
def theme
|
32
|
+
props.theme
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module LucidMaterial
|
2
|
+
module App
|
3
|
+
module Mixin
|
4
|
+
def self.included(base)
|
5
|
+
base.include(::Native::Wrapper)
|
6
|
+
base.extend(::LucidMaterial::App::NativeComponentConstructor)
|
7
|
+
base.extend(::LucidPropDeclaration::Mixin)
|
8
|
+
base.extend(::React::Component::ShouldComponentUpdate)
|
9
|
+
base.extend(::LucidComponent::EventHandler)
|
10
|
+
base.include(::React::Component::Elements)
|
11
|
+
base.include(::React::Component::API)
|
12
|
+
base.include(::React::Component::Callbacks)
|
13
|
+
base.include(::LucidComponent::StoreAPI)
|
14
|
+
base.include(::LucidComponent::StylesSupport)
|
15
|
+
base.include(::LucidApp::API)
|
16
|
+
base.include(::LucidComponent::Initializer)
|
17
|
+
base.include(::React::Component::Features)
|
18
|
+
base.include(::React::Component::Resolution)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module LucidMaterial
|
2
|
+
module App
|
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
|
+
# language=JS
|
10
|
+
%x{
|
11
|
+
base.lucid_react_component = class extends Opal.global.React.Component {
|
12
|
+
constructor(props) {
|
13
|
+
super(props);
|
14
|
+
if (base.$default_state_defined()) {
|
15
|
+
this.state = base.$state().$to_n();
|
16
|
+
} else {
|
17
|
+
this.state = {};
|
18
|
+
};
|
19
|
+
this.state.isomorfeus_store_state = Opal.Isomorfeus.store.native.getState();
|
20
|
+
var current_store_state = this.state.isomorfeus_store_state;
|
21
|
+
if (typeof current_store_state.component_class_state[#{component_name}] !== "undefined") {
|
22
|
+
this.state.component_class_state = {};
|
23
|
+
this.state.component_class_state[#{component_name}] = current_store_state.component_class_state[#{component_name}];
|
24
|
+
} else {
|
25
|
+
this.state.component_class_state = {};
|
26
|
+
this.state.component_class_state[#{component_name}] = {};
|
27
|
+
};
|
28
|
+
this.__ruby_instance = base.$new(this);
|
29
|
+
this.__object_id = this.__ruby_instance.$object_id().$to_s();
|
30
|
+
if (Opal.Isomorfeus.$top_component() == nil) { Opal.Isomorfeus['$top_component='](this); }
|
31
|
+
if (!this.state.component_state) {
|
32
|
+
this.state.component_state = {};
|
33
|
+
this.state.component_state[this.__object_id] = {};
|
34
|
+
};
|
35
|
+
var event_handlers = #{base.event_handlers};
|
36
|
+
for (var i = 0; i < event_handlers.length; i++) {
|
37
|
+
this[event_handlers[i]] = this[event_handlers[i]].bind(this);
|
38
|
+
}
|
39
|
+
var defined_refs = #{base.defined_refs};
|
40
|
+
for (var ref in defined_refs) {
|
41
|
+
if (defined_refs[ref] != null) {
|
42
|
+
this[ref] = function(element) {
|
43
|
+
element = Opal.React.native_element_or_component_to_ruby(element);
|
44
|
+
#{`this.__ruby_instance`.instance_exec(`element`, &`defined_refs[ref]`)}
|
45
|
+
}
|
46
|
+
this[ref] = this[ref].bind(this);
|
47
|
+
} else {
|
48
|
+
this[ref] = Opal.global.React.createRef();
|
49
|
+
}
|
50
|
+
}
|
51
|
+
this.listener = this.listener.bind(this);
|
52
|
+
this.unsubscriber = Opal.Isomorfeus.store.native.subscribe(this.listener);
|
53
|
+
}
|
54
|
+
static get displayName() {
|
55
|
+
return #{component_name};
|
56
|
+
}
|
57
|
+
render() {
|
58
|
+
Opal.React.render_buffer.push([]);
|
59
|
+
Opal.React.active_components.push(this);
|
60
|
+
Opal.React.active_redux_components.push(this.__ruby_instance);
|
61
|
+
#{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
|
62
|
+
Opal.React.active_redux_components.pop();
|
63
|
+
Opal.React.active_components.pop();
|
64
|
+
var children = Opal.React.render_buffer.pop();
|
65
|
+
return Opal.global.React.createElement(Opal.global.LucidApplicationContext.Provider, { value: this.state.isomorfeus_store_state }, children);
|
66
|
+
}
|
67
|
+
listener() {
|
68
|
+
var next_state = Opal.Isomorfeus.store.native.getState();
|
69
|
+
this.setState({ isomorfeus_store_state: next_state });
|
70
|
+
}
|
71
|
+
componentWillUnmount() {
|
72
|
+
if (typeof this.unsubscriber === "function") { this.unsubscriber(); };
|
73
|
+
}
|
74
|
+
validateProp(props, propName, componentName) {
|
75
|
+
try { base.$validate_prop(propName, props[propName]) }
|
76
|
+
catch (e) { return new Error(componentName + " Error: prop validation failed: " + e.message); }
|
77
|
+
return null;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
base.jss_styles = null;
|
81
|
+
base.jss_styles_used = null;
|
82
|
+
base.jss_theme = Opal.global.Mui.createMuiTheme();
|
83
|
+
base.use_styles = null;
|
84
|
+
base.themed_react_component = function(props) {
|
85
|
+
let classes = null;
|
86
|
+
let theme = Opal.global.MuiStyles.useTheme();
|
87
|
+
if (base.jss_styles) {
|
88
|
+
if (!base.use_styles || (Opal.Isomorfeus["$development?"]() && !Object.is(base.jss_styles, base.jss_styles_used))) {
|
89
|
+
base.jss_styles_used = base.jss_styles;
|
90
|
+
let styles = base.jss_styles
|
91
|
+
if (typeof styles === 'function') { styles = styles(theme); }
|
92
|
+
base.use_styles = Opal.global.MuiStyles.makeStyles(styles);
|
93
|
+
}
|
94
|
+
classes = base.use_styles();
|
95
|
+
}
|
96
|
+
let themed_classes_props = Object.assign({}, props, { classes: classes, theme: theme });
|
97
|
+
return Opal.global.React.createElement(base.lucid_react_component, themed_classes_props);
|
98
|
+
}
|
99
|
+
base.react_component = function(props) {
|
100
|
+
let themed_component = Opal.global.React.createElement(base.themed_react_component, props);
|
101
|
+
return Opal.global.React.createElement(Opal.global.MuiStyles.ThemeProvider, { theme: base.jss_theme }, themed_component);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module LucidMaterial
|
2
|
+
module Component
|
3
|
+
module Mixin
|
4
|
+
def self.included(base)
|
5
|
+
base.include(::Native::Wrapper)
|
6
|
+
base.extend(::LucidMaterial::Component::NativeComponentConstructor)
|
7
|
+
base.extend(::LucidPropDeclaration::Mixin)
|
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(::LucidComponent::Initializer)
|
15
|
+
base.include(::React::Component::Features)
|
16
|
+
base.include(::React::Component::Resolution)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module LucidMaterial
|
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
|
+
# language=JS
|
10
|
+
%x{
|
11
|
+
base.lucid_react_component = class extends Opal.global.React.Component {
|
12
|
+
constructor(props) {
|
13
|
+
super(props);
|
14
|
+
if (base.$default_state_defined()) {
|
15
|
+
this.state = base.$state().$to_n();
|
16
|
+
} else {
|
17
|
+
this.state = {};
|
18
|
+
};
|
19
|
+
this.__ruby_instance = base.$new(this);
|
20
|
+
this.__object_id = this.__ruby_instance.$object_id().$to_s();
|
21
|
+
if (!this.state.component_state) {
|
22
|
+
this.state.component_state = {};
|
23
|
+
this.state.component_state[this.__object_id] = {};
|
24
|
+
};
|
25
|
+
var event_handlers = #{base.event_handlers};
|
26
|
+
for (var i = 0; i < event_handlers.length; i++) {
|
27
|
+
this[event_handlers[i]] = this[event_handlers[i]].bind(this);
|
28
|
+
}
|
29
|
+
var defined_refs = #{base.defined_refs};
|
30
|
+
for (var ref in defined_refs) {
|
31
|
+
if (defined_refs[ref] != null) {
|
32
|
+
this[ref] = function(element) {
|
33
|
+
element = Opal.React.native_element_or_component_to_ruby(element);
|
34
|
+
#{`this.__ruby_instance`.instance_exec(`element`, &`defined_refs[ref]`)}
|
35
|
+
}
|
36
|
+
this[ref] = this[ref].bind(this);
|
37
|
+
} else {
|
38
|
+
this[ref] = Opal.global.React.createRef();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
static get displayName() {
|
43
|
+
return #{component_name};
|
44
|
+
}
|
45
|
+
render() {
|
46
|
+
Opal.React.render_buffer.push([]);
|
47
|
+
Opal.React.active_components.push(this);
|
48
|
+
Opal.React.active_redux_components.push(this);
|
49
|
+
#{`this.__ruby_instance`.instance_exec(&`base.render_block`)};
|
50
|
+
Opal.React.active_redux_components.pop();
|
51
|
+
Opal.React.active_components.pop();
|
52
|
+
return Opal.React.render_buffer.pop();
|
53
|
+
}
|
54
|
+
data_access() {
|
55
|
+
return this.context;
|
56
|
+
}
|
57
|
+
shouldComponentUpdate(next_props, next_state) {
|
58
|
+
var next_props_keys = Object.keys(next_props);
|
59
|
+
var this_props_keys = Object.keys(this.props);
|
60
|
+
if (next_props_keys.length !== this_props_keys.length) { return true; }
|
61
|
+
|
62
|
+
var next_state_keys = Object.keys(next_state);
|
63
|
+
var this_state_keys = Object.keys(this.state);
|
64
|
+
if (next_state_keys.length !== this_state_keys.length) { return true; }
|
65
|
+
|
66
|
+
for (var property in next_props) {
|
67
|
+
if (next_props.hasOwnProperty(property)) {
|
68
|
+
if (!this.props.hasOwnProperty(property)) { return true; };
|
69
|
+
if (property == "children") { if (next_props.children !== this.props.children) { return true; }}
|
70
|
+
else if (typeof next_props[property] !== "undefined" && next_props[property] !== null &&
|
71
|
+
typeof next_props[property]['$!='] !== "undefined" &&
|
72
|
+
typeof this.props[property] !== "undefined" && this.props[property] !== null &&
|
73
|
+
typeof this.props[property]['$!='] !== "undefined") {
|
74
|
+
if (#{ !! (`next_props[property]` != `this.props[property]`) }) { return true; };
|
75
|
+
} else if (next_props[property] !== this.props[property]) { return true; };
|
76
|
+
}
|
77
|
+
}
|
78
|
+
for (var property in next_state) {
|
79
|
+
if (next_state.hasOwnProperty(property)) {
|
80
|
+
if (!this.state.hasOwnProperty(property)) { return true; };
|
81
|
+
if (next_state[property] !== null && typeof next_state[property]['$!='] !== "undefined" &&
|
82
|
+
this.state[property] !== null && typeof this.state[property]['$!='] !== "undefined") {
|
83
|
+
if (#{ !! (`next_state[property]` != `this.state[property]`) }) { return true };
|
84
|
+
} else if (next_state[property] !== this.state[property]) { return true };
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return false;
|
88
|
+
}
|
89
|
+
validateProp(props, propName, componentName) {
|
90
|
+
try { base.$validate_prop(propName, props[propName]) }
|
91
|
+
catch (e) { return new Error(componentName + " Error: prop validation failed: " + e.message); }
|
92
|
+
return null;
|
93
|
+
}
|
94
|
+
};
|
95
|
+
base.lucid_react_component.contextType = Opal.global.LucidApplicationContext;
|
96
|
+
base.jss_styles = null;
|
97
|
+
base.jss_styles_used = null;
|
98
|
+
base.use_styles = null;
|
99
|
+
base.react_component = function(props) {
|
100
|
+
let classes = null;
|
101
|
+
let theme = Opal.global.MuiStyles.useTheme();
|
102
|
+
if (base.jss_styles) {
|
103
|
+
if (!base.use_styles || (Opal.Isomorfeus["$development?"]() && !Object.is(base.jss_styles, base.jss_styles_used))) {
|
104
|
+
base.jss_styles_used = base.jss_styles;
|
105
|
+
let styles = base.jss_styles
|
106
|
+
if (typeof styles === 'function') { styles = styles(theme); }
|
107
|
+
base.use_styles = Opal.global.MuiStyles.makeStyles(styles);
|
108
|
+
}
|
109
|
+
classes = base.use_styles();
|
110
|
+
}
|
111
|
+
let themed_classes_props = Object.assign({}, props, { classes: classes, theme: theme });
|
112
|
+
return Opal.global.React.createElement(base.lucid_react_component, themed_classes_props);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|