isomorfeus-preact 10.6.25 → 10.6.26

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 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