view_component_reflex 3.1.12 → 3.1.13.pre0

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,225 @@
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
+ reflex_id: reflex_id
34
+ )
35
+ end
36
+ end
37
+ else
38
+ refresh_component!
39
+ end
40
+ CableReady::Channels.instance[stream].broadcast
41
+ end
42
+
43
+ def stream
44
+ @stream ||= stream_name
45
+ end
46
+
47
+ def stream_to(channel)
48
+ @stream = channel
49
+ end
50
+
51
+ def component_document
52
+ component.tap do |k|
53
+ k.define_singleton_method(:initialize_component) do
54
+ @key = element.dataset[:key]
55
+ end
56
+ end
57
+
58
+ document = Nokogiri::HTML(component.render_in(controller.view_context))
59
+ end
60
+
61
+ def refresh_component!
62
+ CableReady::Channels.instance[stream].morph(
63
+ selector: selector,
64
+ children_only: true,
65
+ html: component_document.css(selector).inner_html,
66
+ permanent_attribute_name: "data-reflex-permanent",
67
+ reflex_id: reflex_id
68
+ )
69
+ end
70
+
71
+ def default_morph
72
+ save_state
73
+ html = if component.can_render_to_string?
74
+ component_document.css(selector).to_html
75
+ else
76
+ controller_document.css(selector).to_html
77
+ end
78
+ morph selector, html
79
+ end
80
+
81
+ def stimulus_reflex_data
82
+ {
83
+ reflex_id: reflex_id,
84
+ xpath_controller: xpath_controller,
85
+ xpath_element: xpath_element,
86
+ target: target,
87
+ reflex_controller: reflex_controller,
88
+ url: url,
89
+ morph: :page,
90
+ attrs: {
91
+ key: element.dataset[:key]
92
+ }
93
+ }
94
+ end
95
+
96
+ def target
97
+ "#{component_class}##{method_name}"
98
+ end
99
+
100
+ def refresh_all!
101
+ refresh!("body")
102
+ end
103
+
104
+ def selector
105
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
106
+ end
107
+
108
+ # SR's delegate_call_to_reflex in channel.rb
109
+ # uses method to gather the method parameters, but since we're abusing
110
+ # method_missing here, that'll always fail
111
+ def method(name)
112
+ component.method(name.to_sym)
113
+ end
114
+
115
+ def respond_to_missing?(name, _ = false)
116
+ !!name.to_proc
117
+ end
118
+
119
+ def method_missing(name, *args, &blk)
120
+ super unless respond_to_missing?(name)
121
+
122
+ state.each do |k, v|
123
+ component.instance_variable_set(k, v)
124
+ end
125
+
126
+ component.send(name, *args, &blk)
127
+
128
+ if @prevent_refresh
129
+ morph :nothing
130
+ else
131
+ default_morph
132
+ end
133
+ end
134
+
135
+ def prevent_refresh!
136
+ @prevent_refresh = true
137
+ end
138
+
139
+ private
140
+
141
+ def component_class
142
+ self.class.component_class
143
+ end
144
+
145
+ def stimulus_controller
146
+ component_class.stimulus_controller
147
+ end
148
+
149
+ def stimulate(target, data)
150
+ data_to_receive = {}
151
+
152
+ stimulus_reflex_data.each do |k, v|
153
+ data_to_receive[k.to_s.camelize(:lower)] = v
154
+ end
155
+
156
+ data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
157
+ o["data-#{k}"] = v
158
+ end
159
+
160
+ data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
161
+ data_to_receive["target"] = target
162
+
163
+ channel.receive data_to_receive
164
+ end
165
+
166
+ def component
167
+ return @component if @component
168
+ @component = component_class.allocate
169
+ reflex = self
170
+ exposed_methods = [
171
+ :params,
172
+ :request,
173
+ :connection,
174
+ :element,
175
+ :refresh!,
176
+ :refresh_all!,
177
+ :stimulus_controller,
178
+ :session,
179
+ :prevent_refresh!,
180
+ :selector,
181
+ :stimulate,
182
+ :stream_to
183
+ ]
184
+ exposed_methods.each do |meth|
185
+ @component.define_singleton_method(meth) do |*a|
186
+ reflex.send(meth, *a)
187
+ end
188
+ end
189
+
190
+ @component.define_singleton_method(:reflex) do
191
+ reflex
192
+ end
193
+
194
+ @component
195
+ end
196
+
197
+ def set_state(new_state = {})
198
+ state_adapter.set_state(request, controller, key, new_state)
199
+ end
200
+
201
+ def key
202
+ element.dataset[:key]
203
+ end
204
+
205
+ def state_adapter
206
+ ViewComponentReflex::Engine.state_adapter
207
+ end
208
+
209
+ def state
210
+ state_adapter.state(request, key)
211
+ end
212
+
213
+ def initial_state
214
+ state_adapter.state(request, "#{key}_initial")
215
+ end
216
+
217
+ def save_state
218
+ new_state = {}
219
+ component.safe_instance_variables.each do |k|
220
+ new_state[k] = component.instance_variable_get(k)
221
+ end
222
+ set_state(new_state)
223
+ end
224
+ end
225
+ end