reactive_component 0.8.4 → 0.8.5
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/CHANGELOG.md +15 -0
- data/app/javascript/reactive_component/lib/reactive_renderer_utils.js +17 -1
- data/lib/reactive_component/engine.rb +10 -0
- data/lib/reactive_component/subscriber_loader.rb +31 -0
- data/lib/reactive_component/version.rb +1 -1
- data/lib/reactive_component.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ec78650feb0396bbe85c2adc0994209dc4d1ab91a6cf0ca49d9692b17e0b316
|
|
4
|
+
data.tar.gz: c2d54ef039a0ea502c593a5eb1e173f509955e3e37b0f6eea1cd78c05ed365d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: caf86cb2646eea037defb27405b486555e70377351c6fe3a61b7d1b00aa33cf330d6ace77a42936e9c93c2bbb992026d0a5a2138137ac6591ff6efd1a45f6c21
|
|
7
|
+
data.tar.gz: fc02fd8569b770ff6b6ed6583cdfbc4fb3dfb2630768eaa7d4f095ce755cc7ecf7617721fa542ca5f76a7a149984cbd5549e4f959911e67b739f96a4e2aa3a22
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.5] - 2026-09-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `morphHooks`: register Idiomorph callbacks that run inside every component's
|
|
7
|
+
morph, for flashing changed values and similar page-wide behaviour, without
|
|
8
|
+
subclassing the controller. See Hooking into the morph.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- An app that does not eager load (development, test) broadcast nothing from a
|
|
12
|
+
process that had not rendered the subscribing component yet, such as a job or
|
|
13
|
+
a turbo-stream request. The engine now loads the components under
|
|
14
|
+
`app/components` that include `ReactiveComponent` on boot and after each
|
|
15
|
+
reload, and only those, so the rest of the app keeps lazy loading. Set
|
|
16
|
+
`ReactiveComponent::SubscriberLoader.paths` to look elsewhere.
|
|
17
|
+
|
|
3
18
|
## [0.8.4] - 2026-09-16
|
|
4
19
|
|
|
5
20
|
### Added
|
|
@@ -34,6 +34,21 @@ export async function decompress(base64) {
|
|
|
34
34
|
return new Response(stream).json()
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// Idiomorph's callbacks, open for the app to hook into: push an object with any
|
|
38
|
+
// of them (a flash on changed numbers, a sound, a counter) and it runs for every
|
|
39
|
+
// component. A hook returning false cancels that node, as Idiomorph expects.
|
|
40
|
+
export const morphHooks = []
|
|
41
|
+
|
|
42
|
+
const HOOK_NAMES = [
|
|
43
|
+
'beforeNodeAdded', 'afterNodeAdded', 'beforeNodeMorphed', 'afterNodeMorphed',
|
|
44
|
+
'beforeNodeRemoved', 'afterNodeRemoved', 'beforeAttributeUpdated'
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
const morphCallbacks = Object.fromEntries(HOOK_NAMES.map(name => [
|
|
48
|
+
name,
|
|
49
|
+
(...args) => morphHooks.reduce((ok, hook) => (hook[name]?.(...args) === false ? false : ok), true)
|
|
50
|
+
]))
|
|
51
|
+
|
|
37
52
|
export function morphElement(element, newHtml) {
|
|
38
53
|
const parser = new DOMParser()
|
|
39
54
|
const doc = parser.parseFromString(`<div>${newHtml}</div>`, "text/html")
|
|
@@ -42,7 +57,8 @@ export function morphElement(element, newHtml) {
|
|
|
42
57
|
if (typeof Idiomorph !== "undefined") {
|
|
43
58
|
Idiomorph.morph(element, newContent, {
|
|
44
59
|
morphStyle: "innerHTML",
|
|
45
|
-
ignoreActiveValue: true
|
|
60
|
+
ignoreActiveValue: true,
|
|
61
|
+
callbacks: morphCallbacks
|
|
46
62
|
})
|
|
47
63
|
} else {
|
|
48
64
|
element.innerHTML = newContent.innerHTML
|
|
@@ -15,6 +15,16 @@ module ReactiveComponent
|
|
|
15
15
|
ReactiveComponent::DataEvaluator.finalize!
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
# A component wires its model up when the class loads, so an app that does
|
|
19
|
+
# not eager load (development, test) would broadcast nothing from a process
|
|
20
|
+
# that has not rendered that component yet: a job, or a turbo-stream
|
|
21
|
+
# request. Load the subscribing components on boot and after each reload.
|
|
22
|
+
initializer 'reactive_component.load_subscribers' do |app|
|
|
23
|
+
next if app.config.eager_load
|
|
24
|
+
|
|
25
|
+
app.config.to_prepare { ReactiveComponent::SubscriberLoader.load_all }
|
|
26
|
+
end
|
|
27
|
+
|
|
18
28
|
initializer 'reactive_component.importmap', before: 'importmap' do |app|
|
|
19
29
|
if defined?(Importmap)
|
|
20
30
|
app.config.importmap.paths <<
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ReactiveComponent
|
|
4
|
+
# A component wires its model up when the class loads, so an app that does
|
|
5
|
+
# not eager load broadcasts nothing from a process that has not rendered that
|
|
6
|
+
# component yet. This loads the components that subscribe, and nothing else.
|
|
7
|
+
module SubscriberLoader
|
|
8
|
+
mattr_accessor :paths, default: ['app/components']
|
|
9
|
+
|
|
10
|
+
SUBSCRIBER = /include\s+ReactiveComponent\b/
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def load_all
|
|
15
|
+
loader = Rails.autoloaders.main
|
|
16
|
+
|
|
17
|
+
files.each { |file| loader.cpath_expected_at(file)&.safe_constantize }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The files under `paths` that include the concern, read rather than
|
|
21
|
+
# loaded, so an app keeps lazy loading for everything else.
|
|
22
|
+
def files
|
|
23
|
+
paths.flat_map do |path|
|
|
24
|
+
dir = Rails.root.join(path)
|
|
25
|
+
next [] unless Dir.exist?(dir)
|
|
26
|
+
|
|
27
|
+
Dir.glob(dir.join('**', '*.rb')).select { |file| File.read(file).match?(SUBSCRIBER) }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/reactive_component.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative 'reactive_component/compiler'
|
|
|
8
8
|
require_relative 'reactive_component/data_evaluator'
|
|
9
9
|
require_relative 'reactive_component/wrapper'
|
|
10
10
|
require_relative 'reactive_component/broadcastable'
|
|
11
|
+
require_relative 'reactive_component/subscriber_loader'
|
|
11
12
|
require_relative 'reactive_component/entity'
|
|
12
13
|
require_relative 'reactive_component/engine' if defined?(Rails::Engine)
|
|
13
14
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: reactive_component
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Przemyslaw Lusar
|
|
@@ -115,6 +115,7 @@ files:
|
|
|
115
115
|
- lib/reactive_component/engine.rb
|
|
116
116
|
- lib/reactive_component/entity.rb
|
|
117
117
|
- lib/reactive_component/erubi.rb
|
|
118
|
+
- lib/reactive_component/subscriber_loader.rb
|
|
118
119
|
- lib/reactive_component/transpiler.rb
|
|
119
120
|
- lib/reactive_component/version.rb
|
|
120
121
|
- lib/reactive_component/wrapper.rb
|