view_component_reflex 3.1.5 → 3.1.10

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: 63a22f733ad6878a7014b1b22ea8de86df54d0f1a7be763f7436998970ea8823
4
- data.tar.gz: e2c6b8ef91bf34ed84a974a8a4e2380c589c8d06dbf85475850390bf7966c599
3
+ metadata.gz: 16b2b912f26f5a3ac4cb26e659d443ce52bca8458154e4cc464ea29d484e9501
4
+ data.tar.gz: 5b320e62171c3ab7e436f39db45c98c52f7274b8f477a6f9ee11af13ac2b1899
5
5
  SHA512:
6
- metadata.gz: 9c231c61349cf8e823f361bd9c2efa768028b2d2c2b794d6f540306068dee0d37fa9d4c72a4e8e8bd6733156f625e320c445dbcd47a6725184755776072612e9
7
- data.tar.gz: 4c5c3727f07b6d9c997386468a13a1c9474e83feb66b0545f27389c9c22e36bac4b33b18b62147e3504fc8f862d60cd35eee36ba1f543d9ad2dcb779be39a502
6
+ metadata.gz: 22d9b03168e43de149a861420b8b819be452ffeb474b8b700cc74af37115cc98849284f2723c920408db60acc957121bf519a1430f65b4efeda503494ccd511f
7
+ data.tar.gz: b0dee0a65bdcf956cebaac0220c615f8fcdbd15d3ecbdeb147129a76612a00556813940416da1938d2f2f4c686898855e8bc5c861eda3441e5fddd4442fe6d17
@@ -1,6 +1,7 @@
1
1
  module ViewComponentReflex
2
2
  class Component < ViewComponent::Base
3
3
  class_attribute :reflex_base_class, default: ViewComponentReflex::Reflex
4
+ attr_reader :key
4
5
 
5
6
  class << self
6
7
  def init_stimulus_reflex
@@ -55,7 +56,7 @@ module ViewComponentReflex
55
56
  end
56
57
 
57
58
  def component_controller(opts_or_tag = :div, opts = {}, &blk)
58
- init_key
59
+ initialize_component
59
60
 
60
61
  tag = :div
61
62
  options = if opts_or_tag.is_a? Hash
@@ -77,11 +78,64 @@ module ViewComponentReflex
77
78
  omitted_from_state.empty?
78
79
  end
79
80
 
80
- # key is required if you're using state
81
- # We can't initialize the session state in the initial method
82
- # because it doesn't have a view_context yet
83
- # This is the next best place to do it
84
- def init_key
81
+ # We can't truly initialize the component without the view_context,
82
+ # which isn't available in the `initialize` method. We require the
83
+ # developer to wrap components in `component_controller`, so this is where
84
+ # we truly initialize the component.
85
+ # This method is overridden in reflex.rb when the component is re-rendered. The
86
+ # override simply sets @key to element.dataset[:key]
87
+ # We don't want it to initialize the state again, and since we're rendering the component
88
+ # outside of the view, we need to skip the initialize_key method as well
89
+ def initialize_component
90
+ initialize_key
91
+ initialize_state
92
+ end
93
+
94
+ # Note to self:
95
+ # This has to be in the Component class because there are situations
96
+ # where the controller is the one rendering the component
97
+ # so we can't rely on the component created by the reflex
98
+ def initialize_state
99
+ return if state_initialized?
100
+ adapter = ViewComponentReflex::Engine.state_adapter
101
+
102
+ # newly mounted
103
+ if !stimulus_reflex? || adapter.state(request, @key).empty?
104
+
105
+ new_state = create_safe_state
106
+
107
+ adapter.wrap_write_async do
108
+ adapter.store_state(request, @key, new_state)
109
+ adapter.store_state(request, "#{@key}_initial", new_state)
110
+ end
111
+
112
+ # updating a mounted component
113
+ else
114
+ initial_state = adapter.state(request, "#{@key}_initial")
115
+
116
+ parameters_changed = []
117
+ adapter.state(request, @key).each do |k, v|
118
+ instance_value = instance_variable_get(k)
119
+ if permit_parameter?(initial_state[k], instance_value)
120
+ parameters_changed << k
121
+ adapter.wrap_write_async do
122
+ adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
123
+ adapter.set_state(request, controller, @key, {k => instance_value})
124
+ end
125
+ else
126
+ instance_variable_set(k, v)
127
+ end
128
+ end
129
+ after_state_initialized(parameters_changed)
130
+ end
131
+ @state_initialized = true
132
+ end
133
+
134
+ def state_initialized?
135
+ @state_initialized
136
+ end
137
+
138
+ def initialize_key
85
139
  # we want the erb file that renders the component. `caller` gives the file name,
86
140
  # and line number, which should be unique. We hash it to make it a nice number
87
141
  erb_file = caller.select { |p| p.match? /.\.html\.(haml|erb|slim)/ }[1]
@@ -137,44 +191,6 @@ module ViewComponentReflex
137
191
  # # no op
138
192
  # end
139
193
 
140
- def key
141
- adapter = ViewComponentReflex::Engine.state_adapter
142
-
143
- # initialize session state
144
- if (!stimulus_reflex? || adapter.state(request, @key).empty?) && !@initialized_state
145
-
146
- new_state = create_safe_state
147
-
148
- adapter.wrap_write_async do
149
- adapter.store_state(request, @key, new_state)
150
- adapter.store_state(request, "#{@key}_initial", new_state)
151
- end
152
- elsif !@initialized_state
153
- initial_state = adapter.state(request, "#{@key}_initial")
154
-
155
- # incoming_params = safe_instance_variables.each_with_object({}) { |var, obj| obj[var] = instance_variable_get(var) }
156
- # receive_params(ViewComponentReflex::Engine.state_adapter.state(request, @key), incoming_params)
157
-
158
- parameters_changed = []
159
- adapter.state(request, @key).each do |k, v|
160
- instance_value = instance_variable_get(k)
161
- if permit_parameter?(initial_state[k], instance_value)
162
- parameters_changed << k
163
- adapter.wrap_write_async do
164
- adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
165
- adapter.set_state(request, controller, @key, {k => instance_value})
166
- end
167
- else
168
- instance_variable_set(k, v)
169
- end
170
- end
171
- after_state_initialized(parameters_changed)
172
- end
173
-
174
- @initialized_state = true
175
- @key
176
- end
177
-
178
194
  def safe_instance_variables
179
195
  instance_variables - unsafe_instance_variables - omitted_from_state
180
196
  end
@@ -185,10 +201,23 @@ module ViewComponentReflex
185
201
  [
186
202
  :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
187
203
  :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
188
- :@helpers, :@controller, :@request, :@tag_builder, :@initialized_state
204
+ :@helpers, :@controller, :@request, :@tag_builder, :@state_initialized,
205
+ :@_content_evaluated, :@_render_in_block
189
206
  ]
190
207
  end
191
208
 
209
+ def content
210
+ if cached_content && !@_render_in_block
211
+ cached_content
212
+ else
213
+ super
214
+ end
215
+ end
216
+
217
+ def cached_content
218
+ @__cached_content__
219
+ end
220
+
192
221
  def create_safe_state
193
222
  new_state = {}
194
223
 
@@ -196,6 +225,9 @@ module ViewComponentReflex
196
225
  safe_instance_variables.each do |k|
197
226
  new_state[k] = instance_variable_get(k)
198
227
  end
228
+
229
+ new_state[:@__cached_content__] = content
230
+
199
231
  new_state
200
232
  end
201
233
 
@@ -5,6 +5,13 @@ module ViewComponentReflex
5
5
  attr_accessor :component_class
6
6
  end
7
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
+
8
15
  def refresh!(primary_selector = nil, *rest)
9
16
  save_state
10
17
 
@@ -13,9 +20,8 @@ module ViewComponentReflex
13
20
  end
14
21
  if primary_selector
15
22
  prevent_refresh!
16
-
17
- controller.process(params[:action])
18
- document = Nokogiri::HTML(controller.response.body)
23
+
24
+ document = controller_document
19
25
  [primary_selector, *rest].each do |s|
20
26
  html = document.css(s)
21
27
  if html.present?
@@ -24,14 +30,13 @@ module ViewComponentReflex
24
30
  html: html.inner_html,
25
31
  children_only: true,
26
32
  permanent_attribute_name: "data-reflex-permanent",
27
- stimulus_reflex: stimulus_reflex_data
28
33
  )
29
34
  end
30
35
  end
31
36
  else
32
37
  refresh_component!
33
38
  end
34
- CableReady::Channels.instance.broadcast
39
+ CableReady::Channels.instance[stream].broadcast
35
40
  end
36
41
 
37
42
  def stream
@@ -42,22 +47,35 @@ module ViewComponentReflex
42
47
  @stream = channel
43
48
  end
44
49
 
45
- def refresh_component!
50
+ def component_document
46
51
  component.tap do |k|
47
- k.define_singleton_method(:key) do
48
- element.dataset[:key]
52
+ k.define_singleton_method(:initialize_component) do
53
+ @key = element.dataset[:key]
49
54
  end
50
55
  end
56
+
51
57
  document = Nokogiri::HTML(component.render_in(controller.view_context))
58
+ end
59
+
60
+ def refresh_component!
52
61
  CableReady::Channels.instance[stream].morph(
53
62
  selector: selector,
54
63
  children_only: true,
55
- html: document.css(selector).inner_html,
64
+ html: component_document.css(selector).inner_html,
56
65
  permanent_attribute_name: "data-reflex-permanent",
57
- stimulus_reflex: stimulus_reflex_data
58
66
  )
59
67
  end
60
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
+
61
79
  def stimulus_reflex_data
62
80
  {
63
81
  reflex_id: reflex_id,
@@ -96,27 +114,20 @@ module ViewComponentReflex
96
114
  !!name.to_proc
97
115
  end
98
116
 
99
- # this is copied out of stimulus_reflex/reflex.rb and modified
100
- def morph(selectors, html = "")
101
- case selectors
102
- when :nothing
103
- @broadcaster = StimulusReflex::NothingBroadcaster.new(self)
104
- else
105
- @broadcaster = StimulusReflex::SelectorBroadcaster.new(self) unless broadcaster.selector?
106
- broadcaster.morphs << [selectors, html]
107
- end
108
- end
109
-
110
117
  def method_missing(name, *args, &blk)
111
- morph :nothing
112
118
  super unless respond_to_missing?(name)
119
+
113
120
  state.each do |k, v|
114
121
  component.instance_variable_set(k, v)
115
122
  end
116
123
 
117
124
  component.send(name, *args, &blk)
118
125
 
119
- refresh! unless @prevent_refresh
126
+ if @prevent_refresh
127
+ morph :nothing
128
+ else
129
+ default_morph
130
+ end
120
131
  end
121
132
 
122
133
  def prevent_refresh!
@@ -182,11 +193,23 @@ module ViewComponentReflex
182
193
  end
183
194
 
184
195
  def set_state(new_state = {})
185
- ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], 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
186
205
  end
187
206
 
188
207
  def state
189
- ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
208
+ state_adapter.state(request, key)
209
+ end
210
+
211
+ def initial_state
212
+ state_adapter.state(request, "#{key}_initial")
190
213
  end
191
214
 
192
215
  def save_state
@@ -9,6 +9,7 @@ module ViewComponentReflex
9
9
  new_state.each do |k, v|
10
10
  state(request, key)[k] = v
11
11
  end
12
+ p new_state
12
13
  store = request.session.instance_variable_get("@by")
13
14
  store.commit_session request, controller.response
14
15
  end
@@ -18,6 +19,7 @@ module ViewComponentReflex
18
19
  new_state.each do |k, v|
19
20
  request.session[key][k] = v
20
21
  end
22
+ p new_state
21
23
  end
22
24
 
23
25
  def self.wrap_write_async
@@ -1,3 +1,3 @@
1
1
  module ViewComponentReflex
2
- VERSION = '3.1.5'
2
+ VERSION = '3.1.10'
3
3
  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: 3.1.5
4
+ version: 3.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua LeBlanc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-29 00:00:00.000000000 Z
11
+ date: 2021-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: 2.28.0
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: '0'
60
+ version: 2.28.0
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: sqlite3
63
63
  requirement: !ruby/object:Gem::Requirement