view_component_reflex 1.0.0 → 1.3.0

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: 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