isomorfeus-preact 10.6.25 → 10.6.26

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5297a6babb3f48a4cebfe2a957fdfcb8b3e3e7de5a928956e0b93f7d3d2741c8
4
- data.tar.gz: a2af099fbf9f129b1fb6054249c99b6387b79ad4ea10493f9b481672afdc8ed2
3
+ metadata.gz: 0d26f73d028c328b0dc47a55e0bb2c7c413df5b8ab7b186952e50949d96dde08
4
+ data.tar.gz: 5952469a0ea71a67f3176f6551e91ed1968dbf0c58131026c6a81d938acc9e75
5
5
  SHA512:
6
- metadata.gz: d4098d558db9b42dc5c35ae1602c83829a80ae64e986fb9f843af1321cec415b314acee4ac292b3c891628b4fc7b1b8628605561a7858af5d5e18d8a6c0d2ad3
7
- data.tar.gz: c726635dc08b8e506551e3e28ada187bd1327bbe30bad51f4095b56e242b412db83d0028c4d33a9608f958986b04d4b8ad090ebff40862d1776db01beb261cc7
6
+ metadata.gz: 3c44c6fc3355ff2f600e9db9debc14804ff7578339af433a5fb271962412a4f530fd401fb592a3267a3845908f328fb94fa9721ca6859a3c701335298a5d3b8f
7
+ data.tar.gz: 65728c2ecc71694b1794d6c4f5d94c5cc9e962db84e4c38569bb36beb6985e408aeaad8e1c77cade61f842c5a8c3d1af0138a80569859b8d3f37a995ddfe74fd
@@ -132,7 +132,7 @@ module Isomorfeus
132
132
  class << self
133
133
  def raise_error(error: nil, error_class: nil, message: nil, stack: nil)
134
134
  error_class = error.class if error
135
-
135
+
136
136
  error_class = RuntimeError unless error_class
137
137
  execution_environment = if on_browser? then 'on Browser'
138
138
  elsif on_ssr? then 'in Server Side Rendering'
@@ -42,7 +42,7 @@ module Isomorfeus
42
42
  end
43
43
 
44
44
  start_time = Time.now if Isomorfeus.development?
45
- pass = 1
45
+ pass = 0
46
46
  # if location_host and scheme are given and if Transport is loaded, connect and then render,
47
47
  # otherwise do not render because only one pass is required
48
48
  ws_scheme = props[:location_scheme] == 'https:' ? 'wss:' : 'ws:'
@@ -84,13 +84,13 @@ module Isomorfeus
84
84
  JAVASCRIPT
85
85
  # execute first render pass
86
86
  begin
87
+ pass += 1
87
88
  first_pass_skipped = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
88
89
  rescue Exception => e
89
90
  Isomorfeus.raise_error(error: e)
90
91
  end
91
92
  # wait for first pass to finish
92
93
  unless first_pass_skipped
93
- pass += 1
94
94
  first_pass_finished, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec('return [global.FirstPassFinished, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false ]')
95
95
  Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
96
96
  unless first_pass_finished
@@ -114,7 +114,7 @@ module Isomorfeus
114
114
  end
115
115
  end
116
116
  end
117
- # build javascript for second render pass
117
+ # build javascript for additional render passes
118
118
  # guard against leaks from first pass, maybe because of a exception
119
119
  javascript = <<~JAVASCRIPT
120
120
  global.Opal.Preact.render_buffer = [];
@@ -136,6 +136,7 @@ module Isomorfeus
136
136
  return [rendered_tree, application_state, ssr_styles, global.Opal.Isomorfeus['$ssr_response_status'](), transport_busy, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false];
137
137
  JAVASCRIPT
138
138
  # execute further render passes
139
+ pass += 1
139
140
  rendered_tree, application_state, @ssr_styles, @ssr_response_status, transport_busy, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
140
141
  start_time = Time.now
141
142
  while transport_busy
@@ -145,10 +146,9 @@ module Isomorfeus
145
146
  sleep 0.01
146
147
  transport_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.Opal.Isomorfeus.Transport["$busy?"]()')
147
148
  end
148
- # execute third render pass
149
149
  pass += 1
150
150
  rendered_tree, application_state, @ssr_styles, @ssr_response_status, transport_busy, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
151
- break if pass > max_passes
151
+ break if pass >= max_passes
152
152
  end
153
153
  javascript = <<~JAVASCRIPT
154
154
  if (typeof global.Opal.Isomorfeus.Transport !== 'undefined') { global.Opal.Isomorfeus.Transport.$disconnect(); }
@@ -171,7 +171,7 @@ module Isomorfeus
171
171
  if Isomorfeus.server_side_rendering
172
172
  render_result = "<script type='application/javascript'>\nServerSideRenderingStateJSON = #{Oj.dump(application_state, mode: :strict)}\n</script>\n" << render_result
173
173
  end
174
- STDERR.puts "PreactViewHelper Server Side Rendering rendered #{pass} passes and took ~#{Time.now - start_time}s" if Isomorfeus.development?
174
+ STDERR.puts "PreactViewHelper Server Side Rendering rendered #{pass} passes and took ~#{Time.now - start_time}s" if Isomorfeus.development? && !skip_ssr
175
175
  render_result
176
176
  end
177
177
 
@@ -1,98 +1,122 @@
1
1
  module Isomorfeus
2
2
  class TopLevel
3
3
  class << self
4
- def mount!
5
- Isomorfeus.init
6
- Isomorfeus::TopLevel.on_ready do
7
- root_element = `document.querySelector('div[data-iso-root]')`
8
- Isomorfeus.raise_error(message: "Isomorfeus root element not found!") unless root_element
9
- component_name = root_element.JS.getAttribute('data-iso-root')
10
- Isomorfeus.env = root_element.JS.getAttribute('data-iso-env')
11
- user_sid = root_element.JS.getAttribute('data-iso-usid')
12
- Isomorfeus.current_user_sid =`JSON.parse(user_sid)` if user_sid
13
- component = nil
14
- begin
15
- component = component_name.constantize
16
- rescue Exception => e
17
- `console.warn("Deferring mount: " + #{e.message})`
18
- @timeout_start = Time.now unless @timeout_start
19
- if (Time.now - @timeout_start) < 10
20
- `setTimeout(Opal.Isomorfeus.TopLevel['$mount!'], 100)`
21
- else
22
- `console.error("Unable to mount '" + #{component_name} + "'!")`
4
+ if on_browser? # execution environment
5
+ def mount!
6
+ Isomorfeus.init
7
+ Isomorfeus::TopLevel.on_ready do
8
+ root_element = `document.querySelector('div[data-iso-root]')`
9
+ Isomorfeus.raise_error(message: "Isomorfeus root element not found!") unless root_element
10
+ component_name = root_element.JS.getAttribute('data-iso-root')
11
+ Isomorfeus.env = root_element.JS.getAttribute('data-iso-env')
12
+ user_sid = root_element.JS.getAttribute('data-iso-usid')
13
+ Isomorfeus.current_user_sid =`JSON.parse(user_sid)` if user_sid
14
+ component = nil
15
+ begin
16
+ component = component_name.constantize
17
+ rescue Exception => e
18
+ `console.warn("Deferring mount: " + #{e.message})`
19
+ @timeout_start = Time.now unless @timeout_start
20
+ if (Time.now - @timeout_start) < 10
21
+ `setTimeout(Opal.Isomorfeus.TopLevel['$mount!'], 100)`
22
+ else
23
+ `console.error("Unable to mount '" + #{component_name} + "'!")`
24
+ end
23
25
  end
24
- end
25
- if component
26
- props_json = root_element.JS.getAttribute('data-iso-props')
27
- props = `Opal.Hash.$new(JSON.parse(props_json))`
28
- raw_hydrated = root_element.JS.getAttribute('data-iso-hydrated')
29
- hydrated = (raw_hydrated && raw_hydrated == "true")
30
- %x{
31
- if (global.ServerSideRenderingStateJSON) {
32
- var state = global.ServerSideRenderingStateJSON;
33
- var keys = Object.keys(state);
34
- for(var i=0; i < keys.length; i++) {
35
- if (Object.keys(state[keys[i]]).length > 0) {
36
- global.Opal.Isomorfeus.store.native.dispatch({ type: keys[i].toUpperCase(), set_state: state[keys[i]] });
26
+ if component
27
+ props_json = root_element.JS.getAttribute('data-iso-props')
28
+ props = `Opal.Hash.$new(JSON.parse(props_json))`
29
+ raw_hydrated = root_element.JS.getAttribute('data-iso-hydrated')
30
+ hydrated = (raw_hydrated && raw_hydrated == "true")
31
+ %x{
32
+ if (global.ServerSideRenderingStateJSON) {
33
+ var state = global.ServerSideRenderingStateJSON;
34
+ var keys = Object.keys(state);
35
+ for(var i=0; i < keys.length; i++) {
36
+ if (Object.keys(state[keys[i]]).length > 0) {
37
+ global.Opal.Isomorfeus.store.native.dispatch({ type: keys[i].toUpperCase(), set_state: state[keys[i]] });
38
+ }
37
39
  }
38
40
  }
39
41
  }
40
- }
41
- Isomorfeus.execute_init_after_store_classes
42
- begin
43
- result = Isomorfeus::TopLevel.mount_component(component, props, root_element, hydrated)
44
- @tried_another_time = false
45
- result
46
- rescue Exception => e
47
- if !@tried_another_time
48
- @tried_another_time = true
49
- `console.warn("Deferring mount: " + #{e.message})`
50
- `console.error(#{e.backtrace.join("\n")})`
51
- `setTimeout(Opal.Isomorfeus.TopLevel['$mount!'], 250)`
52
- else
53
- `console.error("Unable to mount '" + #{component_name} + "'! Error: " + #{e.message} + "!")`
54
- `console.error(#{e.backtrace.join("\n")})`
55
- end
42
+ Isomorfeus.execute_init_after_store_classes
43
+ begin
44
+ result = Isomorfeus::TopLevel.mount_component(component, props, root_element, hydrated)
45
+ @tried_another_time = false
46
+ result
47
+ rescue Exception => e
48
+ if !@tried_another_time
49
+ @tried_another_time = true
50
+ `console.warn("Deferring mount: " + #{e.message})`
51
+ `console.error(#{e.backtrace.join("\n")})`
52
+ `setTimeout(Opal.Isomorfeus.TopLevel['$mount!'], 250)`
53
+ else
54
+ `console.error("Unable to mount '" + #{component_name} + "'! Error: " + #{e.message} + "!")`
55
+ `console.error(#{e.backtrace.join("\n")})`
56
+ end
57
+ end
56
58
  end
57
59
  end
58
60
  end
59
- end
60
61
 
61
- def on_ready(&block)
62
- %x{
63
- function run() { block.$call() };
64
- function ready_fun(fn) {
65
- if (document.readyState === "complete" || document.readyState === "interactive") {
66
- setTimeout(fn, 1);
67
- } else {
68
- document.addEventListener("DOMContentLoaded", fn);
62
+ def on_ready(&block)
63
+ %x{
64
+ function run() { block.$call() };
65
+ function ready_fun(fn) {
66
+ if (document.readyState === "complete" || document.readyState === "interactive") {
67
+ setTimeout(fn, 1);
68
+ } else {
69
+ document.addEventListener("DOMContentLoaded", fn);
70
+ }
69
71
  }
72
+ ready_fun(run);
70
73
  }
71
- ready_fun(run);
72
- }
73
- end
74
+ end
75
+
76
+ def on_ready_mount(component, props = nil, element_query = nil)
77
+ # init in case it hasn't been run yet
78
+ Isomorfeus.init
79
+ on_ready do
80
+ Isomorfeus::TopLevel.mount_component(component, props, element_query)
81
+ end
82
+ end
83
+
84
+ def mount_component(component, props, element_or_query, hydrated = false)
85
+ if `(typeof element_or_query === 'string')` || (`(typeof element_or_query.$class === 'function')` && element_or_query.class == String)
86
+ element = `document.body.querySelector(element_or_query)`
87
+ elsif `(typeof element_or_query.$is_a === 'function')` && element_or_query.is_a?(Browser::Element)
88
+ element = element_or_query.to_n
89
+ else
90
+ element = element_or_query
91
+ end
74
92
 
75
- def on_ready_mount(component, props = nil, element_query = nil)
76
- # init in case it hasn't been run yet
77
- Isomorfeus.init
78
- on_ready do
79
- Isomorfeus::TopLevel.mount_component(component, props, element_query)
93
+ top = Preact.create_element(component, props)
94
+ hydrated ? Preact.hydrate(top, element) : Preact.render(top, element)
95
+ Isomorfeus.top_component = top
80
96
  end
81
- end
97
+ else # execution environment
98
+ attr_accessor :ssr_route_path
99
+ attr_accessor :transport_ws_url
82
100
 
83
- def mount_component(component, props, element_or_query, hydrated = false)
84
- if `(typeof element_or_query === 'string')` || (`(typeof element_or_query.$class === 'function')` && element_or_query.class == String)
85
- element = `document.body.querySelector(element_or_query)`
86
- elsif `(typeof element_or_query.$is_a === 'function')` && element_or_query.is_a?(Browser::Element)
87
- element = element_or_query.to_n
88
- else
89
- element = element_or_query
101
+ def mount!
102
+ # nothing, but keep it for compatibility with browser
90
103
  end
91
104
 
92
- top = Preact.create_element(component, props)
93
- hydrated ? Preact.hydrate(top, element) : Preact.render(top, element)
94
- Isomorfeus.top_component = top
95
- end
105
+ def render_component_to_string(component_name, props)
106
+ component = nil
107
+ %x{
108
+ if (typeof component_name === 'string' || component_name instanceof String) {
109
+ component = component_name.split(".").reduce(function(o, x) {
110
+ return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
111
+ }, Opal.global)
112
+ } else {
113
+ component = component_name;
114
+ }
115
+ }
116
+ component = Isomorfeus.cached_component_class(component_name) unless component
117
+ Preact.render_to_string(Preact.create_element(component, `Opal.Hash.$new(props)`))
118
+ end
119
+ end # execution environment
96
120
  end
97
121
  end
98
122
  end
@@ -13,11 +13,7 @@ if RUBY_ENGINE == 'opal'
13
13
  require 'isomorfeus/preact/config'
14
14
 
15
15
  # allow mounting of components
16
- if on_browser?
17
- require 'isomorfeus/top_level'
18
- else
19
- require 'isomorfeus/top_level_ssr'
20
- end
16
+ require 'isomorfeus/top_level'
21
17
 
22
18
  # nanocss
23
19
  require 'nano_css'
@@ -35,7 +31,7 @@ if RUBY_ENGINE == 'opal'
35
31
  require 'preact/props'
36
32
 
37
33
  # HTML Elements and Fragment support
38
- require 'preact/component/elements'
34
+ require 'preact/elements'
39
35
 
40
36
  # Preact Wrappers
41
37
  require 'preact/context_wrapper'
@@ -47,20 +43,21 @@ if RUBY_ENGINE == 'opal'
47
43
  require 'preact/component/initializer'
48
44
  require 'preact/component/native_component_constructor'
49
45
  require 'preact/state'
50
- require 'preact/component/resolution'
51
46
  require 'preact/component/mixin'
52
47
  require 'preact/component/base'
53
48
 
49
+ # component resolution
50
+ require 'preact/component_resolution'
51
+ class Object
52
+ include Preact::ComponentResolution
53
+ end
54
+
54
55
  # init LucidApplicationContext (Store Provider and Consumer)
55
56
  require 'lucid_app/context'
56
57
  LucidApp::Context.create_application_context
57
58
 
58
- class Object
59
- include Preact::Component::Resolution
60
- end
61
-
59
+ # init auto loader
62
60
  Isomorfeus.zeitwerk = Zeitwerk::Loader.new
63
-
64
61
  Isomorfeus.zeitwerk.push_dir('isomorfeus_preact')
65
62
  require_tree 'isomorfeus_preact', autoload: true
66
63
 
@@ -5,15 +5,33 @@ module LucidApp
5
5
  def theme(theme_hash = nil, &block)
6
6
  theme_hash = block.call if block_given?
7
7
  if theme_hash
8
+ component_name = self.to_s
8
9
  %x{
9
- let css;
10
- if (typeof theme_hash.$to_n === 'function') { css = theme_hash.$to_n(); }
11
- else { css = theme_hash; }
12
- let nano_styles = Opal.global.NanoCSSInstance.sheet(css, "LucidAppTheme");
13
- base.css_theme = #{::LucidComponent::StylesWrapper.new(`nano_styles`)};
10
+ let rule_name = component_name.replace(/:/g, '_');
11
+ let ogni = Opal.global.NanoCSSInstance;
12
+ if (base.css_theme && #{Isomorfeus.production?}) { return base.css_theme; }
13
+ else if(#{Isomorfeus.development?}) {
14
+ if (#{on_browser?}) {
15
+ ogni.delete_from_sheet(rule_name);
16
+ ogni.delete_from_rule_blocks(rule_name);
17
+ ogni.hydrate_force_put = true;
18
+ }
19
+ }
20
+ if (typeof theme_hash.$is_wrapped_style !== 'undefined') {
21
+ base.css_theme = theme_hash;
22
+ } else {
23
+ let css;
24
+ if (typeof theme_hash.$to_n === 'function') { css = theme_hash.$to_n(); }
25
+ else { css = theme_hash; }
26
+ let nano_styles = ogni.sheet(css, rule_name);
27
+ base.css_theme = #{::LucidComponent::StylesWrapper.new(`nano_styles`)};
28
+ }
14
29
  }
15
30
  end
16
- `base.css_theme`
31
+ %x{
32
+ if (!base.css_theme) { return nil; }
33
+ return base.css_theme;
34
+ }
17
35
  end
18
36
  alias_method :theme=, :theme
19
37
  end
@@ -3,12 +3,11 @@ module LucidApp
3
3
  def self.included(base)
4
4
  base.include(::Native::Wrapper)
5
5
  base.extend(::LucidApp::NativeComponentConstructor)
6
- base.include(::Preact::Component::Elements)
6
+ base.include(::Preact::Elements)
7
7
  base.extend(::LucidPropDeclaration::Mixin)
8
8
  base.include(::Preact::Component::Api)
9
9
  base.include(::Preact::Component::Callbacks)
10
10
  base.include(::LucidComponent::Api)
11
- base.include(::LucidComponent::StylesApi)
12
11
  base.include(::LucidApp::Api)
13
12
  base.include(::LucidComponent::Initializer)
14
13
  end
@@ -34,6 +34,40 @@ module LucidComponent
34
34
  end
35
35
  `base.while_loading_block = wl_block`
36
36
  end
37
+
38
+ # styles
39
+ def styles(styles_hash = nil, &block)
40
+ styles_hash = block.call if block_given?
41
+ if styles_hash
42
+ component_name = self.to_s
43
+ %x{
44
+ let rule_name = component_name.replace(/:/g, '_');
45
+ let ogni = Opal.global.NanoCSSInstance;
46
+ if (base.css_styles && #{Isomorfeus.production?}) { return base.css_styles; }
47
+ else if(#{Isomorfeus.development?}) {
48
+ if (#{on_browser?}) {
49
+ ogni.delete_from_sheet(rule_name);
50
+ ogni.delete_from_rule_blocks(rule_name);
51
+ ogni.hydrate_force_put = true;
52
+ }
53
+ }
54
+ if (typeof styles_hash.$is_wrapped_style !== 'undefined') {
55
+ base.css_styles = styles_hash;
56
+ } else {
57
+ let css;
58
+ if (typeof styles_hash.$to_n === 'function') { css = styles_hash.$to_n(); }
59
+ else { css = styles_hash; }
60
+ let nano_styles = ogni.sheet(css, rule_name);
61
+ base.css_styles = #{::LucidComponent::StylesWrapper.new(`nano_styles`)};
62
+ }
63
+ }
64
+ end
65
+ %x{
66
+ if (!base.css_styles) { return nil; }
67
+ return base.css_styles;
68
+ }
69
+ end
70
+ alias_method :styles=, :styles
37
71
  end
38
72
 
39
73
  # stores
@@ -59,6 +93,15 @@ module LucidComponent
59
93
  !!state.preloaded
60
94
  end
61
95
 
96
+ # styles
97
+ def styles
98
+ %x{
99
+ let c = self.$class()
100
+ if (typeof(c.css_styles) === 'undefined') { return nil; }
101
+ return c.css_styles;
102
+ }
103
+ end
104
+
62
105
  # requires transport
63
106
  def current_user
64
107
  Isomorfeus.current_user
@@ -3,12 +3,11 @@ module LucidComponent
3
3
  def self.included(base)
4
4
  base.include(::Native::Wrapper)
5
5
  base.extend(::LucidComponent::NativeComponentConstructor)
6
- base.include(::Preact::Component::Elements)
6
+ base.include(::Preact::Elements)
7
7
  base.extend(::LucidPropDeclaration::Mixin)
8
8
  base.include(::Preact::Component::Api)
9
9
  base.include(::Preact::Component::Callbacks)
10
10
  base.include(::LucidComponent::Api)
11
- base.include(::LucidComponent::StylesApi)
12
11
  base.include(::LucidComponent::Initializer)
13
12
  end
14
13
  end
@@ -4,9 +4,8 @@ module LucidFunc
4
4
  base.include(::LucidFunc::Initializer)
5
5
  base.include(::Preact::FunctionComponent::Api)
6
6
  base.extend(::LucidFunc::NativeComponentConstructor)
7
- base.include(::Preact::Component::Elements)
7
+ base.include(::Preact::Elements)
8
8
  base.include(::LucidComponent::Api)
9
- base.include(::LucidComponent::StylesApi)
10
9
  end
11
10
  end
12
11
  end
@@ -2,7 +2,7 @@ module Preact
2
2
  module FunctionComponent
3
3
  module Mixin
4
4
  def self.included(base)
5
- base.include(::Preact::Component::Elements)
5
+ base.include(::Preact::Elements)
6
6
  base.include(::Preact::FunctionComponent::Initializer)
7
7
  base.include(::Preact::FunctionComponent::Api)
8
8
  base.extend(::Preact::FunctionComponent::NativeComponentConstructor)
data/lib/nano_css.rb CHANGED
@@ -58,27 +58,24 @@ module NanoCSS
58
58
 
59
59
  renderer.putRaw = function (rawCssRule) {
60
60
  // .insertRule() is faster than .appendChild(), that's why we use it in PROD.
61
- // But CSS injected using .insertRule() is not displayed in Chrome Devtools,
62
- // that's why we use .appendChild in DEV.
61
+ // But CSS injected using .insertRule() is not displayed in Chrome Devtools
62
+ var sheet = renderer.sh.sheet;
63
63
  if (process.env.NODE_ENV === 'production') {
64
- var sheet = renderer.sh.sheet;
65
-
66
64
  // Unknown pseudo-selectors will throw, this try/catch swallows all errors.
67
65
  try { sheet.insertRule(rawCssRule, sheet.cssRules.length); }
68
66
  catch (error) {}
69
67
  } else {
70
68
  // Test if .insertRule() works in dev mode. Unknown pseudo-selectors will throw when
71
- // .insertRule() is used, but .appendChild() will not throw.
72
69
  try {
73
- renderer.shTest.sheet.insertRule(rawCssRule, renderer.shTest.sheet.cssRules.length);
70
+ var testSheet = renderer.shTest.sheet;
71
+ testSheet.insertRule(rawCssRule, testSheet.cssRules.length);
72
+ testSheet.deleteRule(testSheet.cssRules.length - 1);
74
73
  } catch (error) {
75
74
  if (config.verbose) {
76
75
  console.error(error);
77
76
  }
78
77
  }
79
-
80
- // Insert pretty-printed CSS for dev mode.
81
- renderer.sh.appendChild(document.createTextNode(rawCssRule));
78
+ sheet.insertRule(rawCssRule, sheet.cssRules.length);
82
79
  }
83
80
  };
84
81
  }
@@ -132,9 +129,15 @@ module NanoCSS
132
129
 
133
130
  %x{
134
131
  self.rule = function (renderer) {
135
- var blocks;
136
132
  if (process.env.NODE_ENV !== 'production') {
137
- blocks = {};
133
+ renderer.rule_blocks = {};
134
+ }
135
+
136
+ renderer.delete_from_rule_blocks = function (rule_name) {
137
+ rule_name = rule_name + '-';
138
+ for(const rule in renderer.rule_blocks) {
139
+ if (rule.startsWith(rule_name)) { delete renderer.rule_blocks[rule]; }
140
+ }
138
141
  }
139
142
 
140
143
  renderer.rule = function (css, block) {
@@ -148,11 +151,11 @@ module NanoCSS
148
151
  );
149
152
  }
150
153
 
151
- if (blocks[block]) {
154
+ if (renderer.rule_blocks[block]) {
152
155
  console.error('nano-css block name "' + block + '" used more than once.');
153
156
  }
154
157
 
155
- blocks[block] = 1;
158
+ renderer.rule_blocks[block] = 1;
156
159
  }
157
160
  }
158
161
 
@@ -167,6 +170,20 @@ module NanoCSS
167
170
 
168
171
  %x{
169
172
  self.sheet = function (renderer) {
173
+ renderer.delete_from_sheet = function(rule_name) {
174
+ let selector_rule_name = "._" + rule_name + "-";
175
+ if (renderer.sh && renderer.sh.sheet) {
176
+ let sheet = renderer.sh.sheet;
177
+ let rules = sheet.cssRules;
178
+ for (let i=rules.length-1;i>=0;i--) {
179
+ let rule = rules.item(i);
180
+ if (rule.cssText.includes(selector_rule_name)) {
181
+ sheet.deleteRule(i);
182
+ }
183
+ }
184
+ }
185
+ }
186
+
170
187
  renderer.sheet = function (map, block) {
171
188
  var result = {};
172
189
 
@@ -248,7 +265,7 @@ module NanoCSS
248
265
  %x{
249
266
  self.hydrate = function (renderer) {
250
267
  var hydrated = {};
251
-
268
+ renderer.hydrate_force_put = false;
252
269
  renderer.hydrate = function (sh) {
253
270
  var cssRules = sh.cssRules || sh.sheet.cssRules;
254
271
 
@@ -262,7 +279,7 @@ module NanoCSS
262
279
  var put = renderer.put;
263
280
 
264
281
  renderer.put = function (selector, css) {
265
- if (selector in hydrated) return;
282
+ if (!renderer.hydrate_force_put && selector in hydrated) return;
266
283
 
267
284
  put(selector, css);
268
285
  };
@@ -5,7 +5,7 @@ module Preact
5
5
  base.include(::Native::Wrapper)
6
6
  base.extend(::Preact::Component::NativeComponentConstructor)
7
7
  base.extend(::LucidPropDeclaration::Mixin)
8
- base.include(::Preact::Component::Elements)
8
+ base.include(::Preact::Elements)
9
9
  base.include(::Preact::Component::Api)
10
10
  base.include(::Preact::Component::Callbacks)
11
11
  base.include(::Preact::Component::Initializer)
@@ -0,0 +1,95 @@
1
+ module Preact
2
+ module ComponentResolution
3
+ def self.included(base)
4
+ base.instance_exec do
5
+ unless method_defined?(:_preact_component_class_resolution_original_const_missing)
6
+ alias _preact_component_class_resolution_original_const_missing const_missing
7
+ end
8
+
9
+ def const_missing(const_name)
10
+ %x{
11
+ if (typeof Opal.global[const_name] !== "undefined" && (const_name[0] === const_name[0].toUpperCase())) {
12
+ var new_const = Opal.Preact.NativeConstantWrapper.$new(Opal.global[const_name], const_name);
13
+ new_const.preact_component = Opal.global[const_name];
14
+ Opal.Object.$const_set(const_name, new_const);
15
+ return new_const;
16
+ } else {
17
+ return #{_preact_component_class_resolution_original_const_missing(const_name)};
18
+ }
19
+ }
20
+ end
21
+
22
+ # this is required for autoloading support, as the component may not be loaded and so its method is not registered.
23
+ # must load it first, done by const_get, and next time the method will be there.
24
+ unless method_defined?(:_preact_component_class_resolution_original_method_missing)
25
+ alias _preact_component_class_resolution_original_method_missing method_missing
26
+ end
27
+
28
+ def method_missing(component_name, *args, &block)
29
+ # check for ruby component and render it
30
+ # otherwise pass on method missing
31
+ %x{
32
+ var constant;
33
+ if (typeof self.iso_preact_const_cache === 'undefined') { self.iso_preact_const_cache = {}; }
34
+ try {
35
+ if (typeof self.iso_preact_const_cache[component_name] !== 'undefined') {
36
+ constant = self.iso_preact_const_cache[component_name]
37
+ } else {
38
+ constant = self.$const_get(component_name);
39
+ self.iso_preact_const_cache[component_name] = constant;
40
+ }
41
+ if (typeof constant.preact_component !== 'undefined') {
42
+ return Opal.Preact.internal_prepare_args_and_render(constant.preact_component, args, block);
43
+ }
44
+ } catch(err) { }
45
+ return #{_preact_component_class_resolution_original_method_missing(component_name, *args, block)};
46
+ }
47
+ end
48
+ end
49
+ end
50
+
51
+ unless method_defined?(:_preact_component_resolution_original_method_missing)
52
+ alias _preact_component_resolution_original_method_missing method_missing
53
+ end
54
+
55
+ def method_missing(component_name, *args, &block)
56
+ # Further on it must check for modules, because $const_get does not take
57
+ # the full nesting into account, as usually its called via $$ with the
58
+ # nesting provided by the compiler.
59
+ %x{
60
+ var constant;
61
+ if (typeof self.iso_preact_const_cache === 'undefined') { self.iso_preact_const_cache = {}; }
62
+
63
+ if (typeof self.iso_preact_const_cache[component_name] !== 'undefined') {
64
+ constant = self.iso_preact_const_cache[component_name]
65
+ } else if (typeof self.$$is_a_module !== 'undefined') {
66
+ try {
67
+ constant = self.$const_get(component_name);
68
+ self.iso_preact_const_cache[component_name] = constant;
69
+ } catch(err) { }
70
+ } else {
71
+ let sc = self.$class();
72
+ try {
73
+ constant = sc.$const_get(component_name);
74
+ self.iso_preact_const_cache[component_name] = constant;
75
+ } catch(err) {
76
+ var module_names = sc.$to_s().split("::");
77
+ var module_name;
78
+ for (var i = module_names.length - 1; i > 0; i--) {
79
+ module_name = module_names.slice(0, i).join('::');
80
+ try {
81
+ constant = sc.$const_get(module_name).$const_get(component_name, false);
82
+ self.iso_preact_const_cache[component_name] = constant;
83
+ break;
84
+ } catch(err) { }
85
+ }
86
+ }
87
+ }
88
+ if (constant && typeof constant.preact_component !== 'undefined') {
89
+ return Opal.Preact.internal_prepare_args_and_render(constant.preact_component, args, block);
90
+ }
91
+ return #{_preact_component_resolution_original_method_missing(component_name, *args, block)};
92
+ }
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,62 @@
1
+ module Preact
2
+ module Elements
3
+ # https://www.w3.org/TR/html52/fullindex.html#index-elements
4
+ # https://www.w3.org/TR/SVG11/eltindex.html
5
+ SUPPORTED_HTML_AND_SVG_ELEMENTS = %w[
6
+ a abbr address area article aside audio
7
+ b base bdi bdo blockquote body br button
8
+ canvas caption cite code col colgroup
9
+ data datalist dd del details dfn dialog div dl dt
10
+ em embed
11
+ fieldset figcaption figure footer form
12
+ h1 h2 h3 h4 h5 h6 head header hr html
13
+ i iframe img input ins
14
+ kbd
15
+ label legend li link
16
+ main map mark meta meter
17
+ nav noscript
18
+ object ol optgroup option output
19
+ p param picture pre progress
20
+ q
21
+ rp rt rtc ruby
22
+ s samp script section select small source span strong style sub summary sup
23
+ table tbody td template textarea tfoot th thead time title tr track
24
+ u ul
25
+ var video
26
+ wbr
27
+ altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion animateTransform
28
+ circle clipPath color-profile cursor
29
+ defs desc
30
+ ellipse
31
+ feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting
32
+ feDisplacementMap feDistantLight feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur
33
+ feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting
34
+ feSpotLight feTile feTurbulence
35
+ filter font font-face font-face-format font-face-name font-face-src font-face-uri foreignObject
36
+ g glyph glyphRef
37
+ hkern
38
+ image
39
+ line linearGradient
40
+ marker mask metadata missing-glyph mpath
41
+ path pattern polygon polyline
42
+ radialGradient rect
43
+ script set stop style svg switch symbol
44
+ text textPath tref tspan
45
+ use
46
+ view vkern
47
+ ]
48
+
49
+ SUPPORTED_HTML_AND_SVG_ELEMENTS.each do |element|
50
+ define_method(element) do |*args, &block|
51
+ `Opal.Preact.internal_prepare_args_and_render(element, args, block)`
52
+ end
53
+ define_method(`element.toUpperCase()`) do |*args, &block|
54
+ `Opal.Preact.internal_prepare_args_and_render(element, args, block)`
55
+ end
56
+ end
57
+
58
+ def Fragment(*args, &block)
59
+ `Opal.Preact.internal_prepare_args_and_render(Opal.global.Preact.Fragment, args, block)`
60
+ end
61
+ end
62
+ end
@@ -1,5 +1,5 @@
1
1
  module Preact
2
- class Options
2
+ class OptionHooks
3
3
  class << self
4
4
  def debounce_rendering(&block)
5
5
  %x{
@@ -79,7 +79,7 @@ module Preact
79
79
  }
80
80
  nil
81
81
  end
82
-
82
+
83
83
  def vnode(&block)
84
84
  %x{
85
85
  const old_hook = Opal.global.Preact.options.unmount;
@@ -1,3 +1,3 @@
1
1
  module Preact
2
- VERSION = '10.6.25'
2
+ VERSION = '10.6.26'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isomorfeus-preact
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.6.25
4
+ version: 10.6.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-02 00:00:00.000000000 Z
11
+ date: 2022-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -233,7 +233,6 @@ files:
233
233
  - lib/isomorfeus/props/validate_hash_proxy.rb
234
234
  - lib/isomorfeus/props/validator.rb
235
235
  - lib/isomorfeus/top_level.rb
236
- - lib/isomorfeus/top_level_ssr.rb
237
236
  - lib/isomorfeus_preact/lucid_app/api.rb
238
237
  - lib/isomorfeus_preact/lucid_app/base.rb
239
238
  - lib/isomorfeus_preact/lucid_app/mixin.rb
@@ -246,7 +245,6 @@ files:
246
245
  - lib/isomorfeus_preact/lucid_component/instance_store_proxy.rb
247
246
  - lib/isomorfeus_preact/lucid_component/mixin.rb
248
247
  - lib/isomorfeus_preact/lucid_component/native_component_constructor.rb
249
- - lib/isomorfeus_preact/lucid_component/styles_api.rb
250
248
  - lib/isomorfeus_preact/lucid_component/styles_wrapper.rb
251
249
  - lib/isomorfeus_preact/lucid_func/base.rb
252
250
  - lib/isomorfeus_preact/lucid_func/initializer.rb
@@ -264,14 +262,14 @@ files:
264
262
  - lib/preact/component/api.rb
265
263
  - lib/preact/component/base.rb
266
264
  - lib/preact/component/callbacks.rb
267
- - lib/preact/component/elements.rb
268
265
  - lib/preact/component/initializer.rb
269
266
  - lib/preact/component/mixin.rb
270
267
  - lib/preact/component/native_component_constructor.rb
271
- - lib/preact/component/resolution.rb
268
+ - lib/preact/component_resolution.rb
272
269
  - lib/preact/context_wrapper.rb
270
+ - lib/preact/elements.rb
273
271
  - lib/preact/native_constant_wrapper.rb
274
- - lib/preact/options.rb
272
+ - lib/preact/option_hooks.rb
275
273
  - lib/preact/params.rb
276
274
  - lib/preact/props.rb
277
275
  - lib/preact/ref.rb
@@ -1,27 +0,0 @@
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
- Preact.render_to_string(Preact.create_element(component, `Opal.Hash.$new(props)`))
24
- end
25
- end
26
- end
27
- end
@@ -1,31 +0,0 @@
1
- module LucidComponent
2
- module StylesApi
3
- def self.included(base)
4
- base.instance_exec do
5
- def styles(styles_hash = nil, &block)
6
- component_name = self.to_s
7
- styles_hash = block.call if block_given?
8
- if styles_hash
9
- %x{
10
- if (typeof styles_hash.$is_wrapped_style !== 'undefined') {
11
- base.css_styles = styles_hash;
12
- } else {
13
- let css;
14
- if (typeof styles_hash.$to_n === 'function') { css = styles_hash.$to_n(); }
15
- else { css = styles_hash; }
16
- let nano_styles = Opal.global.NanoCSSInstance.sheet(css, component_name.replace(/:/g, '_'));
17
- base.css_styles = #{::LucidComponent::StylesWrapper.new(`nano_styles`)};
18
- }
19
- }
20
- end
21
- `base.css_styles`
22
- end
23
- alias_method :styles=, :styles
24
- end
25
-
26
- def styles
27
- `self.$class().css_styles`
28
- end
29
- end
30
- end
31
- end
@@ -1,64 +0,0 @@
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
@@ -1,97 +0,0 @@
1
- module Preact
2
- module Component
3
- module Resolution
4
- def self.included(base)
5
- base.instance_exec do
6
- unless method_defined?(:_preact_component_class_resolution_original_const_missing)
7
- alias _preact_component_class_resolution_original_const_missing const_missing
8
- end
9
-
10
- def const_missing(const_name)
11
- %x{
12
- if (typeof Opal.global[const_name] !== "undefined" && (const_name[0] === const_name[0].toUpperCase())) {
13
- var new_const = Opal.Preact.NativeConstantWrapper.$new(Opal.global[const_name], const_name);
14
- new_const.preact_component = Opal.global[const_name];
15
- Opal.Object.$const_set(const_name, new_const);
16
- return new_const;
17
- } else {
18
- return #{_preact_component_class_resolution_original_const_missing(const_name)};
19
- }
20
- }
21
- end
22
-
23
- # this is required for autoloading support, as the component may not be loaded and so its method is not registered.
24
- # must load it first, done by const_get, and next time the method will be there.
25
- unless method_defined?(:_preact_component_class_resolution_original_method_missing)
26
- alias _preact_component_class_resolution_original_method_missing method_missing
27
- end
28
-
29
- def method_missing(component_name, *args, &block)
30
- # check for ruby component and render it
31
- # otherwise pass on method missing
32
- %x{
33
- var constant;
34
- if (typeof self.iso_preact_const_cache === 'undefined') { self.iso_preact_const_cache = {}; }
35
- try {
36
- if (typeof self.iso_preact_const_cache[component_name] !== 'undefined') {
37
- constant = self.iso_preact_const_cache[component_name]
38
- } else {
39
- constant = self.$const_get(component_name);
40
- self.iso_preact_const_cache[component_name] = constant;
41
- }
42
- if (typeof constant.preact_component !== 'undefined') {
43
- return Opal.Preact.internal_prepare_args_and_render(constant.preact_component, args, block);
44
- }
45
- } catch(err) { }
46
- return #{_preact_component_class_resolution_original_method_missing(component_name, *args, block)};
47
- }
48
- end
49
- end
50
- end
51
-
52
- unless method_defined?(:_preact_component_resolution_original_method_missing)
53
- alias _preact_component_resolution_original_method_missing method_missing
54
- end
55
-
56
- def method_missing(component_name, *args, &block)
57
- # Further on it must check for modules, because $const_get does not take
58
- # the full nesting into account, as usually its called via $$ with the
59
- # nesting provided by the compiler.
60
- %x{
61
- var constant;
62
- if (typeof self.iso_preact_const_cache === 'undefined') { self.iso_preact_const_cache = {}; }
63
-
64
- if (typeof self.iso_preact_const_cache[component_name] !== 'undefined') {
65
- constant = self.iso_preact_const_cache[component_name]
66
- } else if (typeof self.$$is_a_module !== 'undefined') {
67
- try {
68
- constant = self.$const_get(component_name);
69
- self.iso_preact_const_cache[component_name] = constant;
70
- } catch(err) { }
71
- } else {
72
- let sc = self.$class();
73
- try {
74
- constant = sc.$const_get(component_name);
75
- self.iso_preact_const_cache[component_name] = constant;
76
- } catch(err) {
77
- var module_names = sc.$to_s().split("::");
78
- var module_name;
79
- for (var i = module_names.length - 1; i > 0; i--) {
80
- module_name = module_names.slice(0, i).join('::');
81
- try {
82
- constant = sc.$const_get(module_name).$const_get(component_name, false);
83
- self.iso_preact_const_cache[component_name] = constant;
84
- break;
85
- } catch(err) { }
86
- }
87
- }
88
- }
89
- if (constant && typeof constant.preact_component !== 'undefined') {
90
- return Opal.Preact.internal_prepare_args_and_render(constant.preact_component, args, block);
91
- }
92
- return #{_preact_component_resolution_original_method_missing(component_name, *args, block)};
93
- }
94
- end
95
- end
96
- end
97
- end