view_component_reflex 2.3.4 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2a565e11e260df4ecff60b182ac977b06af1407052226ce61b250a19b544248
4
- data.tar.gz: ba3c11853c040b5fe55efa64567017dc70d564bfc159c3cc5eeda17b8c4e1115
3
+ metadata.gz: a3ad9e3707578067e3491f47775c921657589fccb83ce3ffef79215ea104ca8d
4
+ data.tar.gz: 6aeaa003c9c4a2ba99b3aeeaf24ba49488aeb2f71279ee596ae37d9b9c727a72
5
5
  SHA512:
6
- metadata.gz: ff941b717b380704a83fde6e6afb82417ce219684023eb9984c3b08285f108b92b8aab922d24a60990a551c126acd9e1b0f53c94700fc2e38a403cf7ef185855
7
- data.tar.gz: 5d01502b50d7ecf0407eaea0dd1a7e34cee26f23c5b2cc9124b3f210c184452199363b1d429db7754bfb07955e17416b10888b8fc502977825baa5049b524b9a
6
+ metadata.gz: 44bc748544d32080b32d594e72c48b662b95b1f1ff82fabc74c9cb7533013e32eebf4ad2017324849d1869517669cccadda94d25eca9a0ddc605ba8c29b8a58c
7
+ data.tar.gz: 5585167d4e31a5e2d7bec04a33501adfb84f88949c86c61b7c06c56ac48fd4b9205def0cf4fb91d2fe24d43968ff52d9ea860a03adf5650907ebb68083e08a6d
data/README.md CHANGED
@@ -1,332 +1,332 @@
1
- # ViewComponentReflex
2
-
3
- ViewComponentReflex allows you to write reflexes right in your view component code.
4
-
5
- It builds upon [stimulus_reflex](https://github.com/hopsoft/stimulus_reflex) and [view_component](https://github.com/github/view_component)
6
-
7
- ## Usage
8
-
9
- You can add reflexes to your component by adding inheriting from `ViewComponentReflex::Component`.
10
-
11
- This will act as if you created a reflex with the method `my_cool_stuff`. To call this reflex, add `data-reflex="click->MyComponentReflex#my_cool_reflex"`, just like you're
12
- using stimulus reflex.
13
-
14
- ViewComponentReflex will maintain your component's instance variables between renders. You need to include `data-key=<%= key %>` on your root element, as well
15
- as any element that stimulates a reflex. ViewComponent is inherently state-less, so the key is used to reconcile state to its respective component.
16
-
17
- ### Example
18
- ```ruby
19
- # counter_component.rb
20
- class CounterComponent < ViewComponentReflex::Component
21
- def initialize
22
- @count = 0
23
- end
24
-
25
- def increment
26
- @count += 1
27
- end
28
- end
29
- ```
30
-
31
- ```erb
32
- # counter_component.html.erb
33
- <%= component_controller do %>
34
- <p><%= @count %></p>
35
- <%= reflex_tag :increment, :button, "Click" %>
36
- <% end %>
37
- ```
38
-
39
- ## Collections
40
-
41
- In order to reconcile state to components in collections, you can specify a `collection_key` method that returns some
42
- value unique to that component.
43
-
44
- ```ruby
45
- class TodoComponent < ViewComponentReflex::Component
46
- def initialize(todo:)
47
- @todo = todo
48
- end
49
-
50
- def collection_key
51
- @todo.id
52
- end
53
- end
54
- #
55
- <%= render(TodoComponent.with_collection(Todo.all)) %>
56
- ```
57
-
58
- ## API
59
-
60
- ### permit_parameter?(initial_param, new_params)
61
- If a new parameter is passed to the component during rendering, it is used instead of what's in state.
62
- If you're storing instances in state, you can use this to properly compare them.
63
-
64
- ```ruby
65
- def permit_parameter?(initial_param, new_param)
66
- if new_param.instance_of? MyModel
67
- new_param.id == @my_model.id
68
- else
69
- super
70
- end
71
- end
72
- ```
73
-
74
- ### omitted_from_state
75
- Return an array of instance variables you want to omit from state. Only really useful if you're using the session state
76
- adapter, and you have an instance variable that can't be serialized.
77
-
78
- ```ruby
79
- def omitted_from_state
80
- [:@form]
81
- end
82
- ```
83
-
84
- ### reflex_tag(reflex, name, content_or_options_with_block = nil, options = nil, escape = true, &block)
85
- This shares the same definition as `content_tag`, except it accepts a reflex as the first parameter.
86
-
87
- ```erb
88
- <%= reflex_tag :increment, :button, "Click me!" %>
89
- ```
90
-
91
- Would add a click handler to the `increment` method on your component.
92
-
93
- To use a non-click event, specific that with `->` notation
94
-
95
- ```erb
96
- <%= reflex_tag "mouseenter->increment", :button, "Click me!" %>
97
- ```
98
-
99
- ### reflex_data_attributes(reflex)
100
-
101
- This helper will give you the data attributes used in the reflex_tag above if you want to build your own elements.
102
-
103
- Build your own tag:
104
-
105
- ```erb
106
- <%= link_to (image_tag photo.image.url(:medium)), data: reflex_data_attributes(:increment) %>
107
- ```
108
-
109
- Render a ViewComponent
110
-
111
- ```erb
112
- <%= render ButtonComponent.new(data: reflex_data_attributes("mouseenter->increment")) %>
113
- ```
114
-
115
- Make sure that you assign the reflex_data_attributes to the correct element in your component.
116
-
117
- ### collection_key
118
- If you're rendering a component as a collection with `MyComponent.with_collection(SomeCollection)`, you must define this method to return some unique value for the component.
119
- This is used to reconcile state in the background.
120
-
121
- ```ruby
122
- def initialize
123
- @my_model = MyModel.new
124
- end
125
-
126
- def collection_key
127
- @my_model.id
128
- end
129
- ```
130
-
131
- ### stimulate(target, data)
132
- Stimulate another reflex from within your component. This typically requires the key of the component you're stimulating
133
- which can be passed in via parameters.
134
-
135
- ```ruby
136
- def initialize(parent_key)
137
- @parent_key = parent_key
138
- end
139
-
140
- def stimulate_other
141
- stimulate("OtherComponent#method", { key: @parent_key })
142
- end
143
- ```
144
-
145
- ### refresh!(selectors)
146
- Refresh a specific element on the page. Using this will implicitly run `prevent_render!`.
147
- 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
148
-
149
- ```
150
- def my_method
151
- refresh! '#my-special-element', selector
152
- end
153
- ```
154
-
155
- ### selector
156
- Returns the unique selector for this component. Useful to pass to `refresh!` when refreshing custom elements.
157
-
158
- ### prevent_refresh!
159
- By default, VCR will re-render your component after it executes your method. `prevent_refresh!` prevents this from happening.
160
-
161
- ```ruby
162
- def my_method
163
- prevent_refresh!
164
- @foo = Lbar
165
- end # the rendered page will not reflect this change
166
- ```
167
-
168
- ### refresh_all!
169
- Refresh the entire body of the page
170
-
171
- ```ruby
172
- def do_some_global_action
173
- prevent_refresh!
174
- session[:model] = MyModel.new
175
- refresh_all!
176
- end
177
- ```
178
-
179
- ### key
180
- This is a key unique to a particular component. It's used to reconcile state between renders, and should be passed as a data attribute whenever a reflex is called
181
-
182
- ```erb
183
- <button type="button" data-reflex="click->MyComponent#do_something" data-key="<%= key %>">Click me!</button>
184
- ```
185
-
186
- ### component_controller(options = {}, &blk)
187
- This is a view helper to properly connect VCR to the component. It outputs `<div data-controller="my-controller" key=<%= key %></div>`
188
- You *must* wrap your component in this for everything to work properly.
189
-
190
- ```erb
191
- <%= component_controller do %>
192
- <p><%= @count %></p
193
- <% end %>
194
- ```
195
-
196
- ## Custom reflex base class
197
- Reflexes typically inherit from a base ApplicationReflex. You can define the base class for a view_component_reflex by using the `reflex_base_class` method.
198
- The parent class must inherit ViewComponentReflex::Reflex, and will throw an error if it does not.
199
-
200
- ```ruby
201
- class ApplicationReflex < ViewComponentReflex::Reflex
202
-
203
- end
204
-
205
-
206
- class MyComponent < ViewComponentReflex::Component
207
- reflex_base_class ApplicationReflex
208
- end
209
- ```
210
-
211
- ## Common patterns
212
- A lot of the time, you only need to update specific components when changing instance variables. For example, changing `@loading` might only need
213
- to display a spinner somewhere on the page. You can define setters to implicitly render the appropriate pieces of dom whenever that variable is set
214
-
215
- ```ruby
216
- def initialize
217
- @loading = false
218
- end
219
-
220
- def loading=(new_value)
221
- @loading = new_value
222
- refresh! '#loader'
223
- end
224
-
225
- def do_expensive_action
226
- prevent_refresh!
227
-
228
- self.loading = true
229
- execute_it
230
- self.loading = false
231
- end
232
- ```
233
-
234
- ```erb
235
- <%= component_controller do %>
236
- <div id="loader">
237
- <% if @loading %>
238
- <p>Loading...</p>
239
- <% end %>
240
- </div>
241
-
242
- <button type="button" data-reflex="click->MyComponent#do_expensive_action" data-key="<%= key %>">Click me!</button>
243
- <% end
244
- ```
245
-
246
- ## State
247
-
248
- By default, view_component_reflex stores component state in memory. You can optionally set the state adapter
249
- to use the session by changing `config.state_adapter` to `ViewComponentReflex::StateAdapter::Session`
250
-
251
- ## Custom State Adapters
252
-
253
- ViewComponentReflex uses session for its state by default. To change this, add
254
- an initializer to `config/initializers/view_component_reflex.rb`.
255
-
256
- ```ruby
257
- ViewComponentReflex::Engine.configure do |config|
258
- config.state_adapter = YourAdapter
259
- end
260
- ```
261
-
262
- `YourAdapter` should implement
263
-
264
- ```ruby
265
- class YourAdapter
266
- ##
267
- # request - a rails request object
268
- # key - a unique string that identifies the component instance
269
- def self.state(request, key)
270
- # Return state for a given key
271
- end
272
-
273
- ##
274
- # set_state is used to modify the state.
275
- #
276
- # request - a rails request object
277
- # controller - the current controller
278
- # key - a unique string that identifies the component
279
- # new_state - the new state to set
280
- def self.set_state(request, controller, key, new_state)
281
- # update the state
282
- end
283
-
284
-
285
- ##
286
- # store_state is used to replace the state entirely. It only accepts
287
- # a request object, rather than a reflex because it's called from the component's
288
- # side with the component's instance variables.
289
- #
290
- # request - a rails request object
291
- # key - a unique string that identifies the component instance
292
- # new_state - a hash containing the component state
293
- def self.store_state(request, key, new_state = {})
294
- # replace the state
295
- end
296
- end
297
- ```
298
-
299
-
300
- ## Installation
301
- Add this line to your application's Gemfile:
302
-
303
- ```ruby
304
- gem 'view_component_reflex'
305
- ```
306
-
307
- And then execute:
308
- ```bash
309
- $ bundle
310
- ```
311
-
312
- Or install it yourself as:
313
- ```bash
314
- $ gem install view_component_reflex
315
- ```
316
-
317
- # Common problems
318
-
319
- ## Uninitialized constants \<component\>Reflex
320
- A component needs to be wrapped in `<%= component_controller do %>` in order to properly initialize, otherwise the Reflex class won't get created.
321
-
322
- ## License
323
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
324
-
325
- ## Caveats
326
-
327
- State uses session to maintain state as of right now. It also assumes your component view is written with the file extension `.html.erb`
328
-
329
- ## Support me
330
-
331
- <a href="https://www.buymeacoffee.com/jleblanc" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="40" ></a>
332
-
1
+ # ViewComponentReflex
2
+
3
+ ViewComponentReflex allows you to write reflexes right in your view component code.
4
+
5
+ It builds upon [stimulus_reflex](https://github.com/hopsoft/stimulus_reflex) and [view_component](https://github.com/github/view_component)
6
+
7
+ ## Usage
8
+
9
+ You can add reflexes to your component by adding inheriting from `ViewComponentReflex::Component`.
10
+
11
+ This will act as if you created a reflex with the method `my_cool_stuff`. To call this reflex, add `data-reflex="click->MyComponentReflex#my_cool_reflex"`, just like you're
12
+ using stimulus reflex.
13
+
14
+ ViewComponentReflex will maintain your component's instance variables between renders. You need to include `data-key=<%= key %>` on your root element, as well
15
+ as any element that stimulates a reflex. ViewComponent is inherently state-less, so the key is used to reconcile state to its respective component.
16
+
17
+ ### Example
18
+ ```ruby
19
+ # counter_component.rb
20
+ class CounterComponent < ViewComponentReflex::Component
21
+ def initialize
22
+ @count = 0
23
+ end
24
+
25
+ def increment
26
+ @count += 1
27
+ end
28
+ end
29
+ ```
30
+
31
+ ```erb
32
+ # counter_component.html.erb
33
+ <%= component_controller do %>
34
+ <p><%= @count %></p>
35
+ <%= reflex_tag :increment, :button, "Click" %>
36
+ <% end %>
37
+ ```
38
+
39
+ ## Collections
40
+
41
+ In order to reconcile state to components in collections, you can specify a `collection_key` method that returns some
42
+ value unique to that component.
43
+
44
+ ```ruby
45
+ class TodoComponent < ViewComponentReflex::Component
46
+ def initialize(todo:)
47
+ @todo = todo
48
+ end
49
+
50
+ def collection_key
51
+ @todo.id
52
+ end
53
+ end
54
+ #
55
+ <%= render(TodoComponent.with_collection(Todo.all)) %>
56
+ ```
57
+
58
+ ## API
59
+
60
+ ### permit_parameter?(initial_param, new_params)
61
+ If a new parameter is passed to the component during rendering, it is used instead of what's in state.
62
+ If you're storing instances in state, you can use this to properly compare them.
63
+
64
+ ```ruby
65
+ def permit_parameter?(initial_param, new_param)
66
+ if new_param.instance_of? MyModel
67
+ new_param.id == @my_model.id
68
+ else
69
+ super
70
+ end
71
+ end
72
+ ```
73
+
74
+ ### omitted_from_state
75
+ Return an array of instance variables you want to omit from state. Only really useful if you're using the session state
76
+ adapter, and you have an instance variable that can't be serialized.
77
+
78
+ ```ruby
79
+ def omitted_from_state
80
+ [:@form]
81
+ end
82
+ ```
83
+
84
+ ### reflex_tag(reflex, name, content_or_options_with_block = nil, options = nil, escape = true, &block)
85
+ This shares the same definition as `content_tag`, except it accepts a reflex as the first parameter.
86
+
87
+ ```erb
88
+ <%= reflex_tag :increment, :button, "Click me!" %>
89
+ ```
90
+
91
+ Would add a click handler to the `increment` method on your component.
92
+
93
+ To use a non-click event, specific that with `->` notation
94
+
95
+ ```erb
96
+ <%= reflex_tag "mouseenter->increment", :button, "Click me!" %>
97
+ ```
98
+
99
+ ### reflex_data_attributes(reflex)
100
+
101
+ This helper will give you the data attributes used in the reflex_tag above if you want to build your own elements.
102
+
103
+ Build your own tag:
104
+
105
+ ```erb
106
+ <%= link_to (image_tag photo.image.url(:medium)), data: reflex_data_attributes(:increment) %>
107
+ ```
108
+
109
+ Render a ViewComponent
110
+
111
+ ```erb
112
+ <%= render ButtonComponent.new(data: reflex_data_attributes("mouseenter->increment")) %>
113
+ ```
114
+
115
+ Make sure that you assign the reflex_data_attributes to the correct element in your component.
116
+
117
+ ### collection_key
118
+ If you're rendering a component as a collection with `MyComponent.with_collection(SomeCollection)`, you must define this method to return some unique value for the component.
119
+ This is used to reconcile state in the background.
120
+
121
+ ```ruby
122
+ def initialize
123
+ @my_model = MyModel.new
124
+ end
125
+
126
+ def collection_key
127
+ @my_model.id
128
+ end
129
+ ```
130
+
131
+ ### stimulate(target, data)
132
+ Stimulate another reflex from within your component. This typically requires the key of the component you're stimulating
133
+ which can be passed in via parameters.
134
+
135
+ ```ruby
136
+ def initialize(parent_key)
137
+ @parent_key = parent_key
138
+ end
139
+
140
+ def stimulate_other
141
+ stimulate("OtherComponent#method", { key: @parent_key })
142
+ end
143
+ ```
144
+
145
+ ### refresh!(selectors)
146
+ Refresh a specific element on the page. Using this will implicitly run `prevent_render!`.
147
+ 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
148
+
149
+ ```
150
+ def my_method
151
+ refresh! '#my-special-element', selector
152
+ end
153
+ ```
154
+
155
+ ### selector
156
+ Returns the unique selector for this component. Useful to pass to `refresh!` when refreshing custom elements.
157
+
158
+ ### prevent_refresh!
159
+ By default, VCR will re-render your component after it executes your method. `prevent_refresh!` prevents this from happening.
160
+
161
+ ```ruby
162
+ def my_method
163
+ prevent_refresh!
164
+ @foo = Lbar
165
+ end # the rendered page will not reflect this change
166
+ ```
167
+
168
+ ### refresh_all!
169
+ Refresh the entire body of the page
170
+
171
+ ```ruby
172
+ def do_some_global_action
173
+ prevent_refresh!
174
+ session[:model] = MyModel.new
175
+ refresh_all!
176
+ end
177
+ ```
178
+
179
+ ### key
180
+ This is a key unique to a particular component. It's used to reconcile state between renders, and should be passed as a data attribute whenever a reflex is called
181
+
182
+ ```erb
183
+ <button type="button" data-reflex="click->MyComponent#do_something" data-key="<%= key %>">Click me!</button>
184
+ ```
185
+
186
+ ### component_controller(options = {}, &blk)
187
+ This is a view helper to properly connect VCR to the component. It outputs `<div data-controller="my-controller" key=<%= key %></div>`
188
+ You *must* wrap your component in this for everything to work properly.
189
+
190
+ ```erb
191
+ <%= component_controller do %>
192
+ <p><%= @count %></p
193
+ <% end %>
194
+ ```
195
+
196
+ ## Custom reflex base class
197
+ Reflexes typically inherit from a base ApplicationReflex. You can define the base class for a view_component_reflex by using the `reflex_base_class` method.
198
+ The parent class must inherit ViewComponentReflex::Reflex, and will throw an error if it does not.
199
+
200
+ ```ruby
201
+ class ApplicationReflex < ViewComponentReflex::Reflex
202
+
203
+ end
204
+
205
+
206
+ class MyComponent < ViewComponentReflex::Component
207
+ reflex_base_class ApplicationReflex
208
+ end
209
+ ```
210
+
211
+ ## Common patterns
212
+ A lot of the time, you only need to update specific components when changing instance variables. For example, changing `@loading` might only need
213
+ to display a spinner somewhere on the page. You can define setters to implicitly render the appropriate pieces of dom whenever that variable is set
214
+
215
+ ```ruby
216
+ def initialize
217
+ @loading = false
218
+ end
219
+
220
+ def loading=(new_value)
221
+ @loading = new_value
222
+ refresh! '#loader'
223
+ end
224
+
225
+ def do_expensive_action
226
+ prevent_refresh!
227
+
228
+ self.loading = true
229
+ execute_it
230
+ self.loading = false
231
+ end
232
+ ```
233
+
234
+ ```erb
235
+ <%= component_controller do %>
236
+ <div id="loader">
237
+ <% if @loading %>
238
+ <p>Loading...</p>
239
+ <% end %>
240
+ </div>
241
+
242
+ <button type="button" data-reflex="click->MyComponent#do_expensive_action" data-key="<%= key %>">Click me!</button>
243
+ <% end
244
+ ```
245
+
246
+ ## State
247
+
248
+ By default, view_component_reflex stores component state in memory. You can optionally set the state adapter
249
+ to use the session by changing `config.state_adapter` to `ViewComponentReflex::StateAdapter::Session`
250
+
251
+ ## Custom State Adapters
252
+
253
+ ViewComponentReflex uses session for its state by default. To change this, add
254
+ an initializer to `config/initializers/view_component_reflex.rb`.
255
+
256
+ ```ruby
257
+ ViewComponentReflex::Engine.configure do |config|
258
+ config.state_adapter = YourAdapter
259
+ end
260
+ ```
261
+
262
+ `YourAdapter` should implement
263
+
264
+ ```ruby
265
+ class YourAdapter
266
+ ##
267
+ # request - a rails request object
268
+ # key - a unique string that identifies the component instance
269
+ def self.state(request, key)
270
+ # Return state for a given key
271
+ end
272
+
273
+ ##
274
+ # set_state is used to modify the state.
275
+ #
276
+ # request - a rails request object
277
+ # controller - the current controller
278
+ # key - a unique string that identifies the component
279
+ # new_state - the new state to set
280
+ def self.set_state(request, controller, key, new_state)
281
+ # update the state
282
+ end
283
+
284
+
285
+ ##
286
+ # store_state is used to replace the state entirely. It only accepts
287
+ # a request object, rather than a reflex because it's called from the component's
288
+ # side with the component's instance variables.
289
+ #
290
+ # request - a rails request object
291
+ # key - a unique string that identifies the component instance
292
+ # new_state - a hash containing the component state
293
+ def self.store_state(request, key, new_state = {})
294
+ # replace the state
295
+ end
296
+ end
297
+ ```
298
+
299
+
300
+ ## Installation
301
+ Add this line to your application's Gemfile:
302
+
303
+ ```ruby
304
+ gem 'view_component_reflex'
305
+ ```
306
+
307
+ And then execute:
308
+ ```bash
309
+ $ bundle
310
+ ```
311
+
312
+ Or install it yourself as:
313
+ ```bash
314
+ $ gem install view_component_reflex
315
+ ```
316
+
317
+ # Common problems
318
+
319
+ ## Uninitialized constants \<component\>Reflex
320
+ A component needs to be wrapped in `<%= component_controller do %>` in order to properly initialize, otherwise the Reflex class won't get created.
321
+
322
+ ## License
323
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
324
+
325
+ ## Caveats
326
+
327
+ State uses session to maintain state as of right now. It also assumes your component view is written with the file extension `.html.erb`
328
+
329
+ ## Support me
330
+
331
+ <a href="https://www.buymeacoffee.com/jleblanc" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="40" ></a>
332
+