view_component_reflex 1.2.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ed2f845769bba6d5142bef6d6fc601b44841080c49ee47abc0036801f62b145
4
- data.tar.gz: 73e625d1948e5b477def8e098a4a4d55b9a02763c575e1d4bdd4c734e0f208b0
3
+ metadata.gz: 2269d8639ced76028ffe2a5970960d7381c862a75ce36481a84d8cf8886acd6c
4
+ data.tar.gz: c368a487c3a2d97b4207ecb47558877596f9f9dccc7aa63f363598bc72a4eb82
5
5
  SHA512:
6
- metadata.gz: 76c5b53b3acb0fa68084b762ad14fddbaa0aee1d0b9bbe67f33910f088e7b60062bf5dcf61c7703932b2cfa228f4bccfc768e6b9ab64253397e3483efd50cfb5
7
- data.tar.gz: 077a34955920288651b183d77971d30eb4fbfeabe45aaa799d78f2ea242cb46f328d23223508d053e53210c00e9aeb570e9d234b571aba3005e57b6448afd5fc
6
+ metadata.gz: 4822e9370947d8881b8f33ca8a00df19a9458ca31f9da4bc84bcfb438e768f37226a2790f489efe94ec36418f77ed4d32a122a003653ec3120ddc49df5af2a1d
7
+ data.tar.gz: 0f38085c800aa78f43e6df67cec9664115fed2cbce0cefc7fb89dbe2a0b3f624d7adfff1a71e542039af40a6b247744677e96a0115afe6f5f5ad65fb4c2a78df
data/README.md CHANGED
@@ -30,7 +30,7 @@ end
30
30
  # counter_component.html.erb
31
31
  <%= component_controller do %>
32
32
  <p><%= @count %></p>
33
- <button type="button" data-reflex="click->CounterComponentReflex#increment" data-key="<%= key %>">Click</button>
33
+ <%= reflex_tag :increment, :button, "Click" %>
34
34
  <% end %>
35
35
  ```
36
36
 
@@ -39,7 +39,7 @@ end
39
39
  In order to reconcile state to components in collections, you can specify a `collection_key` method that returns some
40
40
  value unique to that component.
41
41
 
42
- ```
42
+ ```ruby
43
43
  class TodoComponent < ViewComponentReflex::Component
44
44
  def initialize(todo:)
45
45
  @todo = todo
@@ -59,6 +59,127 @@ end
59
59
  If a new parameter is passed to the component during rendering, it is used instead of what's in state.
60
60
  If you're storing instances in state, you can use this to properly compare them.
61
61
 
62
+ ```ruby
63
+ def permit_parameter?(initial_param, new_param)
64
+ if new_param.instance_of? MyModel
65
+ new_param.id == @my_model.id
66
+ else
67
+ super
68
+ end
69
+ end
70
+ ```
71
+
72
+ ### omitted_from_state
73
+ Return an array of instance variables you want to omit from state. Useful if you have an object
74
+ that isn't serializable as an instance variable, like a form.
75
+
76
+ ```ruby
77
+ def omitted_from_state
78
+ [:@form]
79
+ end
80
+ ```
81
+
82
+ ### reflex_tag(reflex, name, content_or_options_with_block = nil, options = nil, escape = true, &block)
83
+ This shares the same definition as `content_tag`, except it accepts a reflex as the first parameter.
84
+
85
+ ```erb
86
+ <%= reflex_tag :increment, :button, "Click me!" %>
87
+ ```
88
+
89
+ Would add a click handler to the `increment` method on your component.
90
+
91
+ To use a non-click event, specific that with `->` notiation
92
+
93
+ ```erb
94
+ <%= reflex_tag "mouseenter->increment", :button, "Click me!" %>
95
+ ```
96
+
97
+ ### collection_key
98
+ 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.
99
+ This is used to reconcile state in the background.
100
+
101
+ ```ruby
102
+ def initialize
103
+ @my_model = MyModel.new
104
+ end
105
+
106
+ def collection_key
107
+ @my_model.id
108
+ end
109
+ ```
110
+
111
+ ### prevent_refresh!
112
+ By default, VCR will re-render your component after it executes your method. `revent_refresh!` prevents this from happening.
113
+
114
+ ```ruby
115
+ def my_method
116
+ prevent_refresh!
117
+ @foo = Lbar
118
+ end # the rendered page will not reflect this change
119
+ ```
120
+
121
+ ### refresh_all!
122
+ Refresh the entire body of the page
123
+
124
+ ```ruby
125
+ def do_some_global_action
126
+ prevent_refresh!
127
+ session[:model] = MyModel.new
128
+ refresh_all!
129
+ end
130
+ ```
131
+
132
+ ### key
133
+ 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
134
+
135
+ ```erb
136
+ <button type="button" data-reflex="click->MyComponent#do_something" data-key="<%= key %>">Click me!</button>
137
+ ```
138
+
139
+ ### component_controller(options = {}, &blk)
140
+ This is a view helper to properly connect VCR to the component. It outputs `<div data-controller="my-controller" key=<%= key %></div>`
141
+ You *must* wrap your component in this for everything to work properly.
142
+
143
+ ```erb
144
+ <%= component_controller do %>
145
+ <p><%= @count %></p
146
+ <% end %>
147
+ ```
148
+
149
+ ## Common patterns
150
+ A lot of the time, you only need to update specific components when changing instance variables. For example, changing `@loading` might only need
151
+ 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
152
+
153
+ ```ruby
154
+ def initialize
155
+ @loading = false
156
+ end
157
+
158
+ def loading=(new_value)
159
+ @loading = new_value
160
+ refresh! '#loader'
161
+ end
162
+
163
+ def do_expensive_action
164
+ prevent_refresh!
165
+
166
+ self.loading = true
167
+ execute_it
168
+ self.loading = false
169
+ end
170
+ ```
171
+
172
+ ```erb
173
+ <%= component_controller do %>
174
+ <div id="loader">
175
+ <% if @loading %>
176
+ <p>Loading...</p>
177
+ <% end %>
178
+ </div>
179
+
180
+ <button type="button" data-reflex="click->MyComponent#do_expensive_action" data-key="<%= key %>">Click me!</button>
181
+ <% end
182
+ ```
62
183
 
63
184
  ## Custom State Adapters
64
185
 
@@ -43,7 +43,11 @@ module ViewComponentReflex
43
43
  component.instance_variable_set(k, v)
44
44
  end
45
45
  name.to_proc.call(component, *args)
46
- refresh!
46
+ refresh! unless @prevent_refresh
47
+ end
48
+
49
+ def prevent_refresh!
50
+ @prevent_refresh = true
47
51
  end
48
52
 
49
53
  define_method :component_class do
@@ -62,7 +66,7 @@ module ViewComponentReflex
62
66
  return @component if @component
63
67
  @component = component_class.allocate
64
68
  reflex = self
65
- exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller]
69
+ exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session, :prevent_refresh!]
66
70
  exposed_methods.each do |meth|
67
71
  @component.define_singleton_method(meth) do |*a|
68
72
  reflex.send(meth, *a)
@@ -98,15 +102,23 @@ module ViewComponentReflex
98
102
  helpers.controller.instance_variable_get(:@stimulus_reflex)
99
103
  end
100
104
 
101
- def component_controller(opts = {}, &blk)
105
+ def component_controller(opts_or_tag = :div, opts = {}, &blk)
102
106
  self.class.init_stimulus_reflex
103
107
  init_key
104
- opts[:data] = {
108
+
109
+ tag = :div
110
+ if opts_or_tag.is_a? Hash
111
+ options = opts_or_tag
112
+ else
113
+ tag = opts_or_tag
114
+ options = opts
115
+ end
116
+ options[:data] = {
105
117
  controller: self.class.stimulus_controller,
106
118
  key: key,
107
- **(opts[:data] || {})
119
+ **(options[:data] || {})
108
120
  }
109
- content_tag :div, capture(&blk), opts
121
+ content_tag tag, capture(&blk), options
110
122
  end
111
123
 
112
124
  # key is required if you're using state
@@ -121,6 +133,24 @@ module ViewComponentReflex
121
133
  @key = key
122
134
  end
123
135
 
136
+ def reflex_tag(reflex, name, content_or_options_with_block = {}, options = {}, escape = true, &block)
137
+ action, method = reflex.to_s.split("->")
138
+ if method.nil?
139
+ method = action
140
+ action = "click"
141
+ end
142
+ data_attributes = {
143
+ reflex: "#{action}->#{self.class.name}##{method}",
144
+ key: key
145
+ }
146
+ if content_or_options_with_block.is_a?(Hash)
147
+ merge_data_attributes(content_or_options_with_block, data_attributes)
148
+ else
149
+ merge_data_attributes(options, data_attributes)
150
+ end
151
+ content_tag(name, content_or_options_with_block, options, escape, &block)
152
+ end
153
+
124
154
  def collection_key
125
155
  nil
126
156
  end
@@ -129,6 +159,10 @@ module ViewComponentReflex
129
159
  initial_param != new_param
130
160
  end
131
161
 
162
+ def omitted_from_state
163
+ []
164
+ end
165
+
132
166
  def key
133
167
  # initialize session state
134
168
  if !stimulus_reflex? || session[@key].nil?
@@ -141,7 +175,7 @@ module ViewComponentReflex
141
175
  :@helpers, :@controller, :@request, :@content
142
176
  ]
143
177
  instance_variables.reject { |k| blacklist.include?(k) }.each do |k|
144
- new_state[k] = instance_variable_get(k)
178
+ new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
145
179
  end
146
180
  ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
147
181
  ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
@@ -155,5 +189,16 @@ module ViewComponentReflex
155
189
  end
156
190
  @key
157
191
  end
192
+
193
+ private
194
+
195
+ def merge_data_attributes(options, attributes)
196
+ data = options[:data]
197
+ if data.nil?
198
+ options[:data] = attributes
199
+ else
200
+ options[:data].merge! attributes
201
+ end
202
+ end
158
203
  end
159
204
  end
@@ -1,3 +1,3 @@
1
- module ViewComponentReflex
2
- VERSION = '1.2.0'
3
- end
1
+ module ViewComponentReflex
2
+ VERSION = '1.6.1'
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: 1.2.0
4
+ version: 1.6.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-06-20 00:00:00.000000000 Z
11
+ date: 2020-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails