view_component_reflex 1.7.2 → 2.1.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46d3bc691137a986b26a9487624f004cf9625079040130a035129d12f3f52829
|
4
|
+
data.tar.gz: 9793628bd7618163d9c0014f887d8ef791ac25c2f168dd8c7cbb45e6c55f0839
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 014e4d807f719ccb361d9bd800ed599164c498c8e0a947820495982d63a1c07c7409041394d24e247701ec2510b27fe2bbfaee9829733946fe8e51ce630f8e80
|
7
|
+
data.tar.gz: 11cb4beef6ec931032d5b228fa43aee432ce8973fffa10c4391a8577d4788607937d3eb19b41650f778bbdd3cdad94f05e6eb69c0f97a7fdddc8056973f0152c
|
data/README.md
CHANGED
@@ -108,6 +108,33 @@ def collection_key
|
|
108
108
|
end
|
109
109
|
```
|
110
110
|
|
111
|
+
### stimulate(target, data)
|
112
|
+
Stimulate another reflex from within your component. This typically requires the key of the component you're stimulating
|
113
|
+
which can be passed in via parameters.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
def initialize(parent_key)
|
117
|
+
@parent_key = parent_key
|
118
|
+
end
|
119
|
+
|
120
|
+
def stimulate_other
|
121
|
+
stimulate("OtherComponent#method", { key: @parent_key })
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
### refresh!(selectors)
|
126
|
+
Refresh a specific element on the page. Using this will implicitly run `prevent_render!`.
|
127
|
+
If you want to render a specific element, as well as the component, a common pattern would be to pass `selector` as one of the parameters
|
128
|
+
|
129
|
+
```
|
130
|
+
def my_method
|
131
|
+
refresh! '#my-special-element', selector
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
### selector
|
136
|
+
Returns the unique selector for this component. Useful to pass to `refresh!` when refreshing custom elements.
|
137
|
+
|
111
138
|
### prevent_refresh!
|
112
139
|
By default, VCR will re-render your component after it executes your method. `revent_refresh!` prevents this from happening.
|
113
140
|
|
@@ -2,95 +2,12 @@ module ViewComponentReflex
|
|
2
2
|
class Component < ViewComponent::Base
|
3
3
|
class << self
|
4
4
|
def init_stimulus_reflex
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
"args" => [],
|
12
|
-
"attrs" => element.attributes.to_h,
|
13
|
-
"selectors" => ["body"],
|
14
|
-
"target" => "#{self.class.name}##{method_name}",
|
15
|
-
"url" => request.url,
|
16
|
-
"permanent_attribute_name" => "data-reflex-permanent"
|
17
|
-
}
|
18
|
-
end
|
19
|
-
|
20
|
-
def refresh_all!
|
21
|
-
refresh!("body")
|
22
|
-
end
|
23
|
-
|
24
|
-
# SR's delegate_call_to_reflex in channel.rb
|
25
|
-
# uses method to gather the method parameters, but since we're abusing
|
26
|
-
# method_missing here, that'll always fail
|
27
|
-
def method(name)
|
28
|
-
name.to_sym.to_proc
|
29
|
-
end
|
30
|
-
|
31
|
-
def respond_to_missing?(name, _ = false)
|
32
|
-
!!name.to_proc
|
33
|
-
end
|
34
|
-
|
35
|
-
before_reflex do |a|
|
36
|
-
a.send a.method_name
|
37
|
-
throw :abort
|
38
|
-
end
|
39
|
-
|
40
|
-
def method_missing(name, *args)
|
41
|
-
super unless respond_to_missing?(name)
|
42
|
-
state.each do |k, v|
|
43
|
-
component.instance_variable_set(k, v)
|
44
|
-
end
|
45
|
-
name.to_proc.call(component, *args)
|
46
|
-
refresh! unless @prevent_refresh
|
47
|
-
end
|
48
|
-
|
49
|
-
def prevent_refresh!
|
50
|
-
@prevent_refresh = true
|
51
|
-
end
|
52
|
-
|
53
|
-
define_method :component_class do
|
54
|
-
@component_class ||= klass
|
55
|
-
end
|
56
|
-
|
57
|
-
private :component_class
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def stimulus_controller
|
62
|
-
component_class.stimulus_controller
|
63
|
-
end
|
64
|
-
|
65
|
-
def component
|
66
|
-
return @component if @component
|
67
|
-
@component = component_class.allocate
|
68
|
-
reflex = self
|
69
|
-
exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session, :prevent_refresh!]
|
70
|
-
exposed_methods.each do |meth|
|
71
|
-
@component.define_singleton_method(meth) do |*a|
|
72
|
-
reflex.send(meth, *a)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
@component
|
76
|
-
end
|
77
|
-
|
78
|
-
def set_state(new_state = {})
|
79
|
-
ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
|
80
|
-
end
|
81
|
-
|
82
|
-
def state
|
83
|
-
ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
|
84
|
-
end
|
85
|
-
|
86
|
-
def save_state
|
87
|
-
new_state = {}
|
88
|
-
component.safe_instance_variables.each do |k|
|
89
|
-
new_state[k] = component.instance_variable_get(k)
|
90
|
-
end
|
91
|
-
set_state(new_state)
|
92
|
-
end
|
93
|
-
})
|
5
|
+
if name.include? "::"
|
6
|
+
@stimulus_reflex ||= module_parent.const_set(name.split("::").last + "Reflex", Class.new(Reflex))
|
7
|
+
else
|
8
|
+
@stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(Reflex))
|
9
|
+
end
|
10
|
+
@stimulus_reflex.component_class = self
|
94
11
|
end
|
95
12
|
end
|
96
13
|
|
@@ -121,6 +38,10 @@ module ViewComponentReflex
|
|
121
38
|
content_tag tag, capture(&blk), options
|
122
39
|
end
|
123
40
|
|
41
|
+
def can_render_to_string?
|
42
|
+
omitted_from_state.empty?
|
43
|
+
end
|
44
|
+
|
124
45
|
# key is required if you're using state
|
125
46
|
# We can't initialize the session state in the initial method
|
126
47
|
# because it doesn't have a view_context yet
|
@@ -174,7 +95,11 @@ module ViewComponentReflex
|
|
174
95
|
else
|
175
96
|
initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
|
176
97
|
ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
|
177
|
-
|
98
|
+
instance_value = instance_variable_get(k)
|
99
|
+
if permit_parameter?(initial_state[k], instance_value)
|
100
|
+
ViewComponentReflex::Engine.state_adapter.set_state(request, controller, "#{@key}_initial", { k => instance_value })
|
101
|
+
ViewComponentReflex::Engine.state_adapter.set_state(request, controller, @key, { k => instance_value })
|
102
|
+
else
|
178
103
|
instance_variable_set(k, v)
|
179
104
|
end
|
180
105
|
end
|
@@ -192,7 +117,7 @@ module ViewComponentReflex
|
|
192
117
|
[
|
193
118
|
:@view_context, :@lookup_context, :@view_renderer, :@view_flow,
|
194
119
|
:@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
|
195
|
-
:@helpers, :@controller, :@request, :@
|
120
|
+
:@helpers, :@controller, :@request, :@tag_builder
|
196
121
|
]
|
197
122
|
end
|
198
123
|
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module ViewComponentReflex
|
2
|
+
class Reflex < StimulusReflex::Reflex
|
3
|
+
include CableReady::Broadcaster
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :component_class
|
7
|
+
end
|
8
|
+
|
9
|
+
def refresh!(primary_selector = nil, *rest)
|
10
|
+
save_state
|
11
|
+
|
12
|
+
if primary_selector.nil? && !component.can_render_to_string?
|
13
|
+
primary_selector = selector
|
14
|
+
end
|
15
|
+
if primary_selector
|
16
|
+
prevent_refresh!
|
17
|
+
|
18
|
+
controller.process(url_params[:action])
|
19
|
+
document = Nokogiri::HTML(controller.response.body)
|
20
|
+
[primary_selector, *rest].each do |s|
|
21
|
+
html = document.css(s)
|
22
|
+
if html.present?
|
23
|
+
cable_ready[channel.stream_name].morph(
|
24
|
+
selector: s,
|
25
|
+
html: html.inner_html,
|
26
|
+
children_only: true,
|
27
|
+
permanent_attribute_name: "data-reflex-permanent"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
else
|
32
|
+
refresh_component!
|
33
|
+
end
|
34
|
+
cable_ready.broadcast
|
35
|
+
end
|
36
|
+
|
37
|
+
def refresh_component!
|
38
|
+
component.tap do |k|
|
39
|
+
k.define_singleton_method(:key) do
|
40
|
+
element.dataset[:key]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
document = Nokogiri::HTML(controller.render_component_to_string(component))
|
44
|
+
cable_ready[channel.stream_name].morph(
|
45
|
+
selector: selector,
|
46
|
+
children_only: true,
|
47
|
+
html: document.css(selector).inner_html,
|
48
|
+
permanent_attribute_name: "data-reflex-permanent"
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def refresh_all!
|
53
|
+
refresh!("body")
|
54
|
+
end
|
55
|
+
|
56
|
+
def selector
|
57
|
+
"[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
|
58
|
+
end
|
59
|
+
|
60
|
+
# SR's delegate_call_to_reflex in channel.rb
|
61
|
+
# uses method to gather the method parameters, but since we're abusing
|
62
|
+
# method_missing here, that'll always fail
|
63
|
+
def method(name)
|
64
|
+
name.to_sym.to_proc
|
65
|
+
end
|
66
|
+
|
67
|
+
def respond_to_missing?(name, _ = false)
|
68
|
+
!!name.to_proc
|
69
|
+
end
|
70
|
+
|
71
|
+
before_reflex do |a|
|
72
|
+
a.send a.method_name
|
73
|
+
throw :abort
|
74
|
+
end
|
75
|
+
|
76
|
+
def method_missing(name, *args)
|
77
|
+
super unless respond_to_missing?(name)
|
78
|
+
state.each do |k, v|
|
79
|
+
component.instance_variable_set(k, v)
|
80
|
+
end
|
81
|
+
name.to_proc.call(component, *args)
|
82
|
+
refresh! unless @prevent_refresh
|
83
|
+
end
|
84
|
+
|
85
|
+
def prevent_refresh!
|
86
|
+
@prevent_refresh = true
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def component_class
|
92
|
+
self.class.component_class
|
93
|
+
end
|
94
|
+
|
95
|
+
def stimulus_controller
|
96
|
+
component_class.stimulus_controller
|
97
|
+
end
|
98
|
+
|
99
|
+
def stimulate(target, data)
|
100
|
+
dataset = {}
|
101
|
+
data.each do |k, v|
|
102
|
+
dataset["data-#{k}"] = v.to_s
|
103
|
+
end
|
104
|
+
channel.receive({
|
105
|
+
"target" => target,
|
106
|
+
"attrs" => element.attributes.to_h.symbolize_keys,
|
107
|
+
"dataset" => dataset
|
108
|
+
})
|
109
|
+
end
|
110
|
+
|
111
|
+
def component
|
112
|
+
return @component if @component
|
113
|
+
@component = component_class.allocate
|
114
|
+
reflex = self
|
115
|
+
exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session, :prevent_refresh!, :selector, :stimulate]
|
116
|
+
exposed_methods.each do |meth|
|
117
|
+
@component.define_singleton_method(meth) do |*a|
|
118
|
+
reflex.send(meth, *a)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@component
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_state(new_state = {})
|
125
|
+
ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
|
126
|
+
end
|
127
|
+
|
128
|
+
def state
|
129
|
+
ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
|
130
|
+
end
|
131
|
+
|
132
|
+
def save_state
|
133
|
+
new_state = {}
|
134
|
+
component.safe_instance_variables.each do |k|
|
135
|
+
new_state[k] = component.instance_variable_get(k)
|
136
|
+
end
|
137
|
+
set_state(new_state)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: view_component_reflex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua LeBlanc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
71
|
- app/components/view_component_reflex/component.rb
|
72
|
+
- app/reflexes/view_component_reflex/reflex.rb
|
72
73
|
- lib/view_component_reflex.rb
|
73
74
|
- lib/view_component_reflex/engine.rb
|
74
75
|
- lib/view_component_reflex/state_adapter/memory.rb
|