view_component_reflex 1.0.0 → 1.3.0

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: f7e9a4ab35ecb85fef158f336121ffd080f26d344bbf804abfc1fd85849b6734
4
- data.tar.gz: 202ab52b2ad27cca0b823cb13d71b0389d6dba68e35e1f92da2ef601a2690125
3
+ metadata.gz: 30533287ce1445add7dba2ebed5013ed80e792de560fa9c930f3e13dcbd612d7
4
+ data.tar.gz: bf84f573e602b373855848b2fbe61245967e4f16e7a420b03c1b6414aa1c8c73
5
5
  SHA512:
6
- metadata.gz: aeccacfe56978cc599fabdba202e645950cbf09a52c1a42bcdd12620018a2299a6858c0cda5c13ad644d0e78c766cffef55d46227874ed54d4944c0cef70f042
7
- data.tar.gz: e5e7798417649a6233513a741f7c891e05abe15c941e2ade30bb7a9200b8c9e93039ba54a656cff05bf5a1dab886dd1dfc7bfcc4b42539853ce2cac70857c606
6
+ metadata.gz: 47dc5ab24c0711778b07b8460207b1e532c944173d4df2cc8fe33447868b96a9043ad972b5a9672a0ea09ad323199b7cfa15327634199d3218e69e6c797f4196
7
+ data.tar.gz: d9dbc21f77baf9c73c20352a5163c8af52317a0138393d4128cc34bb60e903227e62e28e0f0e0ad92f4fa10d4206f79d295c74582774b93fefffd14801fe5c44
data/README.md CHANGED
@@ -14,16 +14,16 @@ as any element that stimulates a reflex. ViewComponent is inherently state-less,
14
14
 
15
15
  ### Example
16
16
  ```ruby
17
- # counter_component.rb
18
- class CounterComponent < ViewComponentReflex::Component
19
- def initialize
20
- @count = 0
21
- end
22
-
23
- def increment
24
- @count += 1
25
- end
26
- end
17
+ # counter_component.rb
18
+ class CounterComponent < ViewComponentReflex::Component
19
+ def initialize
20
+ @count = 0
21
+ end
22
+
23
+ def increment
24
+ @count += 1
25
+ end
26
+ end
27
27
  ```
28
28
 
29
29
  ```erb
@@ -34,6 +34,42 @@ as any element that stimulates a reflex. ViewComponent is inherently state-less,
34
34
  <% end %>
35
35
  ```
36
36
 
37
+ ## Collections
38
+
39
+ In order to reconcile state to components in collections, you can specify a `collection_key` method that returns some
40
+ value unique to that component.
41
+
42
+ ```
43
+ class TodoComponent < ViewComponentReflex::Component
44
+ def initialize(todo:)
45
+ @todo = todo
46
+ end
47
+
48
+ def collection_key
49
+ @todo.id
50
+ end
51
+ end
52
+ #
53
+ <%= render(TodoComponent.with_collection(Todo.all)) %>
54
+ ```
55
+
56
+ ## API
57
+
58
+ ### permit_parameter?(initial_param, new_params)
59
+ If a new parameter is passed to the component during rendering, it is used instead of what's in state.
60
+ If you're storing instances in state, you can use this to properly compare them.
61
+
62
+ ### omitted_from_state
63
+ Return an array of instance variables you want to omit from state. Useful if you have an object
64
+ that isn't serializable as an instance variable, like a form.
65
+
66
+ ```
67
+ def omitted_from_state
68
+ [:@form]
69
+ end
70
+ ```
71
+
72
+
37
73
  ## Custom State Adapters
38
74
 
39
75
  ViewComponentReflex uses session for its state by default. To change this, add
@@ -57,13 +93,13 @@ class YourAdapter
57
93
  end
58
94
 
59
95
  ##
60
- # set_state is used to modify the state. It accepts a reflex, which gives you
61
- # access to the request, as well as the controller and other useful objects.
96
+ # set_state is used to modify the state.
62
97
  #
63
- # reflex - The reflex instance that's trying to set the state
98
+ # request - a rails request object
99
+ # controller - the current controller
64
100
  # key - a unique string that identifies the component
65
101
  # new_state - the new state to set
66
- def self.set_state(reflex, key, new_state)
102
+ def self.set_state(request, controller, key, new_state)
67
103
  # update the state
68
104
  end
69
105
 
@@ -4,16 +4,16 @@ module ViewComponentReflex
4
4
  def init_stimulus_reflex
5
5
  klass = self
6
6
  @stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(StimulusReflex::Reflex) {
7
- def refresh!(primary_selector = "[data-controller=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]", *selectors)
7
+ def refresh!(primary_selector = "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]", *selectors)
8
8
  save_state
9
9
  @channel.send :render_page_and_broadcast_morph, self, [primary_selector, *selectors], {
10
- dataset: element.dataset.to_h,
11
- args: [],
12
- attrs: element.attributes.to_h,
13
- selectors: ["body"],
14
- target: "#{self.class.name}##{method_name}",
15
- url: request.url,
16
- permanentAttributeName: "data-reflex-permanent"
10
+ "dataset" => element.dataset.to_h,
11
+ "args" => [],
12
+ "attrs" => element.attributes.to_h,
13
+ "selectors" => ["body"],
14
+ "target" => "#{self.class.name}##{method_name}",
15
+ "url" => request.url,
16
+ "permanent_attribute_name" => "data-reflex-permanent"
17
17
  }
18
18
  end
19
19
 
@@ -62,7 +62,7 @@ module ViewComponentReflex
62
62
  return @component if @component
63
63
  @component = component_class.allocate
64
64
  reflex = self
65
- exposed_methods = [:element, :refresh!, :refresh_all!, :stimulus_controller]
65
+ exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session]
66
66
  exposed_methods.each do |meth|
67
67
  @component.define_singleton_method(meth) do |*a|
68
68
  reflex.send(meth, *a)
@@ -72,7 +72,7 @@ module ViewComponentReflex
72
72
  end
73
73
 
74
74
  def set_state(new_state = {})
75
- ViewComponentReflex::Engine.state_adapter.set_state(self, element.dataset[:key], new_state)
75
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
76
76
  end
77
77
 
78
78
  def state
@@ -98,24 +98,42 @@ module ViewComponentReflex
98
98
  helpers.controller.instance_variable_get(:@stimulus_reflex)
99
99
  end
100
100
 
101
- def component_controller(&blk)
102
- opts = {data: {controller: self.class.stimulus_controller, key: key}}
103
- view_context.content_tag :div, capture(&blk), opts
101
+ def component_controller(opts = {}, &blk)
102
+ self.class.init_stimulus_reflex
103
+ init_key
104
+ opts[:data] = {
105
+ controller: self.class.stimulus_controller,
106
+ key: key,
107
+ **(opts[:data] || {})
108
+ }
109
+ content_tag :div, capture(&blk), opts
104
110
  end
105
111
 
106
112
  # key is required if you're using state
107
113
  # We can't initialize the session state in the initial method
108
114
  # because it doesn't have a view_context yet
109
115
  # This is the next best place to do it
110
- def key
111
- self.class.init_stimulus_reflex
116
+ def init_key
112
117
  # we want the erb file that renders the component. `caller` gives the file name,
113
118
  # and line number, which should be unique. We hash it to make it a nice number
114
119
  key = caller.select { |p| p.include? ".html.erb" }[1]&.hash.to_s
115
- if @key.nil? || @key.empty?
116
- @key = key
117
- end
120
+ key += collection_key.to_s if collection_key
121
+ @key = key
122
+ end
123
+
124
+ def collection_key
125
+ nil
126
+ end
118
127
 
128
+ def permit_parameter?(initial_param, new_param)
129
+ initial_param != new_param
130
+ end
131
+
132
+ def omitted_from_state
133
+ []
134
+ end
135
+
136
+ def key
119
137
  # initialize session state
120
138
  if !stimulus_reflex? || session[@key].nil?
121
139
  new_state = {}
@@ -124,15 +142,19 @@ module ViewComponentReflex
124
142
  blacklist = [
125
143
  :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
126
144
  :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
127
- :@helpers, :@controller, :@request
145
+ :@helpers, :@controller, :@request, :@content
128
146
  ]
129
147
  instance_variables.reject { |k| blacklist.include?(k) }.each do |k|
130
- new_state[k] = instance_variable_get(k)
148
+ new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
131
149
  end
132
150
  ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
151
+ ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
133
152
  else
153
+ initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
134
154
  ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
135
- instance_variable_set(k, v)
155
+ unless permit_parameter?(initial_state[k], instance_variable_get(k))
156
+ instance_variable_set(k, v)
157
+ end
136
158
  end
137
159
  end
138
160
  @key
@@ -5,12 +5,12 @@ module ViewComponentReflex
5
5
  request.session[key] ||= {}
6
6
  end
7
7
 
8
- def self.set_state(reflex, key, new_state)
8
+ def self.set_state(request, controller, key, new_state)
9
9
  new_state.each do |k, v|
10
- state(reflex.request, key)[k] = v
10
+ state(request, key)[k] = v
11
11
  end
12
- store = reflex.request.session.instance_variable_get("@by")
13
- store.commit_session reflex.request, reflex.controller.response
12
+ store = request.session.instance_variable_get("@by")
13
+ store.commit_session request, controller.response
14
14
  end
15
15
 
16
16
  def self.store_state(request, key, new_state = {})
@@ -1,3 +1,3 @@
1
1
  module ViewComponentReflex
2
- VERSION = '1.0.0'
2
+ VERSION = '1.3.0'
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: 1.0.0
4
+ version: 1.3.0
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-18 00:00:00.000000000 Z
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails