view_component_reflex 3.1.10 → 3.1.11

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.
@@ -1,12 +1,12 @@
1
- require "stimulus_reflex"
2
- require 'view_component_reflex/reflex_factory'
3
- require "view_component_reflex/state_adapter/base"
4
- require "view_component_reflex/state_adapter/session"
5
- require "view_component_reflex/state_adapter/memory"
6
- require "view_component_reflex/state_adapter/redis"
7
- require "view_component_reflex/reflex"
8
- require "view_component_reflex/engine"
9
-
10
- module ViewComponentReflex
11
- # Your code goes here...
12
- end
1
+ require "stimulus_reflex"
2
+ require 'view_component_reflex/reflex_factory'
3
+ require "view_component_reflex/state_adapter/base"
4
+ require "view_component_reflex/state_adapter/session"
5
+ require "view_component_reflex/state_adapter/memory"
6
+ require "view_component_reflex/state_adapter/redis"
7
+ require "view_component_reflex/reflex"
8
+ require "view_component_reflex/engine"
9
+
10
+ module ViewComponentReflex
11
+ # Your code goes here...
12
+ end
@@ -1,37 +1,37 @@
1
- module ViewComponentReflex
2
- class Engine < ::Rails::Engine
3
-
4
- mattr_accessor :state_adapter
5
- Engine.state_adapter = StateAdapter::Session
6
-
7
- config.to_prepare do
8
- StimulusReflex::Channel.class_eval do
9
- unless instance_methods.include?(:receive_original)
10
- alias_method :receive_original, :receive
11
- def receive(data)
12
- target = data["target"].to_s
13
- reflex_name, _ = target.split("#")
14
- reflex_name = reflex_name.camelize
15
- component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
16
- component = begin
17
- component_name.constantize
18
- rescue
19
- # Since every reflex runs through this monkey patch, we're just going to ignore the ones that aren't for components
20
- end
21
-
22
- if component&.respond_to?(:init_stimulus_reflex)
23
- component.init_stimulus_reflex
24
- else
25
- p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
26
- end
27
- receive_original(data)
28
- end
29
- end
30
- end
31
- end
32
-
33
- def self.configure
34
- yield self if block_given?
35
- end
36
- end
37
- end
1
+ module ViewComponentReflex
2
+ class Engine < ::Rails::Engine
3
+
4
+ mattr_accessor :state_adapter
5
+ Engine.state_adapter = StateAdapter::Session
6
+
7
+ config.to_prepare do
8
+ StimulusReflex::Channel.class_eval do
9
+ unless instance_methods.include?(:receive_original)
10
+ alias_method :receive_original, :receive
11
+ def receive(data)
12
+ target = data["target"].to_s
13
+ reflex_name, _ = target.split("#")
14
+ reflex_name = reflex_name.camelize
15
+ component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
16
+ component = begin
17
+ component_name.constantize
18
+ rescue
19
+ # Since every reflex runs through this monkey patch, we're just going to ignore the ones that aren't for components
20
+ end
21
+
22
+ if component&.respond_to?(:init_stimulus_reflex)
23
+ component.init_stimulus_reflex
24
+ else
25
+ p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
26
+ end
27
+ receive_original(data)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.configure
34
+ yield self if block_given?
35
+ end
36
+ end
37
+ end
@@ -1,223 +1,223 @@
1
- module ViewComponentReflex
2
- class Reflex < StimulusReflex::Reflex
3
-
4
- class << self
5
- attr_accessor :component_class
6
- end
7
-
8
- # pretty sure I can't memoize this because we need
9
- # to re-render every time
10
- def controller_document
11
- controller.process(params[:action])
12
- Nokogiri::HTML(controller.response.body)
13
- end
14
-
15
- def refresh!(primary_selector = nil, *rest)
16
- save_state
17
-
18
- if primary_selector.nil? && !component.can_render_to_string?
19
- primary_selector = selector
20
- end
21
- if primary_selector
22
- prevent_refresh!
23
-
24
- document = controller_document
25
- [primary_selector, *rest].each do |s|
26
- html = document.css(s)
27
- if html.present?
28
- CableReady::Channels.instance[stream].morph(
29
- selector: s,
30
- html: html.inner_html,
31
- children_only: true,
32
- permanent_attribute_name: "data-reflex-permanent",
33
- )
34
- end
35
- end
36
- else
37
- refresh_component!
38
- end
39
- CableReady::Channels.instance[stream].broadcast
40
- end
41
-
42
- def stream
43
- @stream ||= stream_name
44
- end
45
-
46
- def stream_to(channel)
47
- @stream = channel
48
- end
49
-
50
- def component_document
51
- component.tap do |k|
52
- k.define_singleton_method(:initialize_component) do
53
- @key = element.dataset[:key]
54
- end
55
- end
56
-
57
- document = Nokogiri::HTML(component.render_in(controller.view_context))
58
- end
59
-
60
- def refresh_component!
61
- CableReady::Channels.instance[stream].morph(
62
- selector: selector,
63
- children_only: true,
64
- html: component_document.css(selector).inner_html,
65
- permanent_attribute_name: "data-reflex-permanent",
66
- )
67
- end
68
-
69
- def default_morph
70
- save_state
71
- html = if component.can_render_to_string?
72
- component_document.css(selector).to_html
73
- else
74
- controller_document.css(selector).to_html
75
- end
76
- morph selector, html
77
- end
78
-
79
- def stimulus_reflex_data
80
- {
81
- reflex_id: reflex_id,
82
- xpath_controller: xpath_controller,
83
- xpath_element: xpath_element,
84
- target: target,
85
- reflex_controller: reflex_controller,
86
- url: url,
87
- morph: :page,
88
- attrs: {
89
- key: element.dataset[:key]
90
- }
91
- }
92
- end
93
-
94
- def target
95
- "#{component_class}##{method_name}"
96
- end
97
-
98
- def refresh_all!
99
- refresh!("body")
100
- end
101
-
102
- def selector
103
- "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
104
- end
105
-
106
- # SR's delegate_call_to_reflex in channel.rb
107
- # uses method to gather the method parameters, but since we're abusing
108
- # method_missing here, that'll always fail
109
- def method(name)
110
- component.method(name.to_sym)
111
- end
112
-
113
- def respond_to_missing?(name, _ = false)
114
- !!name.to_proc
115
- end
116
-
117
- def method_missing(name, *args, &blk)
118
- super unless respond_to_missing?(name)
119
-
120
- state.each do |k, v|
121
- component.instance_variable_set(k, v)
122
- end
123
-
124
- component.send(name, *args, &blk)
125
-
126
- if @prevent_refresh
127
- morph :nothing
128
- else
129
- default_morph
130
- end
131
- end
132
-
133
- def prevent_refresh!
134
- @prevent_refresh = true
135
- end
136
-
137
- private
138
-
139
- def component_class
140
- self.class.component_class
141
- end
142
-
143
- def stimulus_controller
144
- component_class.stimulus_controller
145
- end
146
-
147
- def stimulate(target, data)
148
- data_to_receive = {}
149
-
150
- stimulus_reflex_data.each do |k, v|
151
- data_to_receive[k.to_s.camelize(:lower)] = v
152
- end
153
-
154
- data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
155
- o["data-#{k}"] = v
156
- end
157
-
158
- data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
159
- data_to_receive["target"] = target
160
-
161
- channel.receive data_to_receive
162
- end
163
-
164
- def component
165
- return @component if @component
166
- @component = component_class.allocate
167
- reflex = self
168
- exposed_methods = [
169
- :params,
170
- :request,
171
- :connection,
172
- :element,
173
- :refresh!,
174
- :refresh_all!,
175
- :stimulus_controller,
176
- :session,
177
- :prevent_refresh!,
178
- :selector,
179
- :stimulate,
180
- :stream_to
181
- ]
182
- exposed_methods.each do |meth|
183
- @component.define_singleton_method(meth) do |*a|
184
- reflex.send(meth, *a)
185
- end
186
- end
187
-
188
- @component.define_singleton_method(:reflex) do
189
- reflex
190
- end
191
-
192
- @component
193
- end
194
-
195
- def set_state(new_state = {})
196
- state_adapter.set_state(request, controller, key, new_state)
197
- end
198
-
199
- def key
200
- element.dataset[:key]
201
- end
202
-
203
- def state_adapter
204
- ViewComponentReflex::Engine.state_adapter
205
- end
206
-
207
- def state
208
- state_adapter.state(request, key)
209
- end
210
-
211
- def initial_state
212
- state_adapter.state(request, "#{key}_initial")
213
- end
214
-
215
- def save_state
216
- new_state = {}
217
- component.safe_instance_variables.each do |k|
218
- new_state[k] = component.instance_variable_get(k)
219
- end
220
- set_state(new_state)
221
- end
222
- end
223
- end
1
+ module ViewComponentReflex
2
+ class Reflex < StimulusReflex::Reflex
3
+
4
+ class << self
5
+ attr_accessor :component_class
6
+ end
7
+
8
+ # pretty sure I can't memoize this because we need
9
+ # to re-render every time
10
+ def controller_document
11
+ controller.process(params[:action])
12
+ Nokogiri::HTML(controller.response.body)
13
+ end
14
+
15
+ def refresh!(primary_selector = nil, *rest)
16
+ save_state
17
+
18
+ if primary_selector.nil? && !component.can_render_to_string?
19
+ primary_selector = selector
20
+ end
21
+ if primary_selector
22
+ prevent_refresh!
23
+
24
+ document = controller_document
25
+ [primary_selector, *rest].each do |s|
26
+ html = document.css(s)
27
+ if html.present?
28
+ CableReady::Channels.instance[stream].morph(
29
+ selector: s,
30
+ html: html.inner_html,
31
+ children_only: true,
32
+ permanent_attribute_name: "data-reflex-permanent",
33
+ )
34
+ end
35
+ end
36
+ else
37
+ refresh_component!
38
+ end
39
+ CableReady::Channels.instance[stream].broadcast
40
+ end
41
+
42
+ def stream
43
+ @stream ||= stream_name
44
+ end
45
+
46
+ def stream_to(channel)
47
+ @stream = channel
48
+ end
49
+
50
+ def component_document
51
+ component.tap do |k|
52
+ k.define_singleton_method(:initialize_component) do
53
+ @key = element.dataset[:key]
54
+ end
55
+ end
56
+
57
+ document = Nokogiri::HTML(component.render_in(controller.view_context))
58
+ end
59
+
60
+ def refresh_component!
61
+ CableReady::Channels.instance[stream].morph(
62
+ selector: selector,
63
+ children_only: true,
64
+ html: component_document.css(selector).inner_html,
65
+ permanent_attribute_name: "data-reflex-permanent",
66
+ )
67
+ end
68
+
69
+ def default_morph
70
+ save_state
71
+ html = if component.can_render_to_string?
72
+ component_document.css(selector).to_html
73
+ else
74
+ controller_document.css(selector).to_html
75
+ end
76
+ morph selector, html
77
+ end
78
+
79
+ def stimulus_reflex_data
80
+ {
81
+ reflex_id: reflex_id,
82
+ xpath_controller: xpath_controller,
83
+ xpath_element: xpath_element,
84
+ target: target,
85
+ reflex_controller: reflex_controller,
86
+ url: url,
87
+ morph: :page,
88
+ attrs: {
89
+ key: element.dataset[:key]
90
+ }
91
+ }
92
+ end
93
+
94
+ def target
95
+ "#{component_class}##{method_name}"
96
+ end
97
+
98
+ def refresh_all!
99
+ refresh!("body")
100
+ end
101
+
102
+ def selector
103
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
104
+ end
105
+
106
+ # SR's delegate_call_to_reflex in channel.rb
107
+ # uses method to gather the method parameters, but since we're abusing
108
+ # method_missing here, that'll always fail
109
+ def method(name)
110
+ component.method(name.to_sym)
111
+ end
112
+
113
+ def respond_to_missing?(name, _ = false)
114
+ !!name.to_proc
115
+ end
116
+
117
+ def method_missing(name, *args, &blk)
118
+ super unless respond_to_missing?(name)
119
+
120
+ state.each do |k, v|
121
+ component.instance_variable_set(k, v)
122
+ end
123
+
124
+ component.send(name, *args, &blk)
125
+
126
+ if @prevent_refresh
127
+ morph :nothing
128
+ else
129
+ default_morph
130
+ end
131
+ end
132
+
133
+ def prevent_refresh!
134
+ @prevent_refresh = true
135
+ end
136
+
137
+ private
138
+
139
+ def component_class
140
+ self.class.component_class
141
+ end
142
+
143
+ def stimulus_controller
144
+ component_class.stimulus_controller
145
+ end
146
+
147
+ def stimulate(target, data)
148
+ data_to_receive = {}
149
+
150
+ stimulus_reflex_data.each do |k, v|
151
+ data_to_receive[k.to_s.camelize(:lower)] = v
152
+ end
153
+
154
+ data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
155
+ o["data-#{k}"] = v
156
+ end
157
+
158
+ data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
159
+ data_to_receive["target"] = target
160
+
161
+ channel.receive data_to_receive
162
+ end
163
+
164
+ def component
165
+ return @component if @component
166
+ @component = component_class.allocate
167
+ reflex = self
168
+ exposed_methods = [
169
+ :params,
170
+ :request,
171
+ :connection,
172
+ :element,
173
+ :refresh!,
174
+ :refresh_all!,
175
+ :stimulus_controller,
176
+ :session,
177
+ :prevent_refresh!,
178
+ :selector,
179
+ :stimulate,
180
+ :stream_to
181
+ ]
182
+ exposed_methods.each do |meth|
183
+ @component.define_singleton_method(meth) do |*a|
184
+ reflex.send(meth, *a)
185
+ end
186
+ end
187
+
188
+ @component.define_singleton_method(:reflex) do
189
+ reflex
190
+ end
191
+
192
+ @component
193
+ end
194
+
195
+ def set_state(new_state = {})
196
+ state_adapter.set_state(request, controller, key, new_state)
197
+ end
198
+
199
+ def key
200
+ element.dataset[:key]
201
+ end
202
+
203
+ def state_adapter
204
+ ViewComponentReflex::Engine.state_adapter
205
+ end
206
+
207
+ def state
208
+ state_adapter.state(request, key)
209
+ end
210
+
211
+ def initial_state
212
+ state_adapter.state(request, "#{key}_initial")
213
+ end
214
+
215
+ def save_state
216
+ new_state = {}
217
+ component.safe_instance_variables.each do |k|
218
+ new_state[k] = component.instance_variable_get(k)
219
+ end
220
+ set_state(new_state)
221
+ end
222
+ end
223
+ end