view_component_reflex 1.0.1 → 1.4.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: 82d4e40f0f58fd47d6c163e9054b3497eb46ec96a1e963037d96793dbea35530
4
- data.tar.gz: d169f2e5a7816ee41f56cf033037c61ebb4085b201c85185c8df1cccadbbadb6
3
+ metadata.gz: f79604a043d4aa353ade5fec1bb3c1d7f263352304555fe3fe70dfd35fc921b9
4
+ data.tar.gz: 88259eb0924cf1508df64f5bb3565fac61134871d2ac210c3166c560bb0f028e
5
5
  SHA512:
6
- metadata.gz: 61562e94b88bc140382c480f61e0b9e6afb7024177378978b14fd02a7d2658042fc530798ccafb65cea2092d0438a968b32361afde80b0fb23deea73b2475f5a
7
- data.tar.gz: b7b4d73cca02d7a2b70d4b43570e09a2a7acede221d9516c29aa68232d421f05cb27da0a743f532369f0db068e01c30c7ed207c426e48a9b2e1fd7857383efab
6
+ metadata.gz: 30d400ca7ace85a4f9bc9b25b6e4cdddfceb6518c980cbcb35f6e6f2216b03a5615cb882b91f9f9097bbce2b2495d306698b4c5bbedecae4259e97750d396bc9
7
+ data.tar.gz: 1c70cda5b7f89057079b86729d97a47a5b429e5f0bdd56732c4695841fe933c0ff57bf1b5143ec0fb7c54cac67bbc8a9c32d031337f33ec91949eb420eba67ac
data/README.md CHANGED
@@ -34,6 +34,42 @@ end
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,7 +4,7 @@ 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
10
  "dataset" => element.dataset.to_h,
@@ -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)
@@ -72,7 +76,7 @@ module ViewComponentReflex
72
76
  end
73
77
 
74
78
  def set_state(new_state = {})
75
- ViewComponentReflex::Engine.state_adapter.set_state(self, element.dataset[:key], new_state)
79
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
76
80
  end
77
81
 
78
82
  def state
@@ -98,24 +102,42 @@ module ViewComponentReflex
98
102
  helpers.controller.instance_variable_get(:@stimulus_reflex)
99
103
  end
100
104
 
101
- def component_controller(&blk)
102
- opts = {data: {controller: self.class.stimulus_controller, key: key}}
103
- view_context.content_tag :div, capture(&blk), opts
105
+ def component_controller(opts = {}, &blk)
106
+ self.class.init_stimulus_reflex
107
+ init_key
108
+ opts[:data] = {
109
+ controller: self.class.stimulus_controller,
110
+ key: key,
111
+ **(opts[:data] || {})
112
+ }
113
+ content_tag :div, capture(&blk), opts
104
114
  end
105
115
 
106
116
  # key is required if you're using state
107
117
  # We can't initialize the session state in the initial method
108
118
  # because it doesn't have a view_context yet
109
119
  # This is the next best place to do it
110
- def key
111
- self.class.init_stimulus_reflex
120
+ def init_key
112
121
  # we want the erb file that renders the component. `caller` gives the file name,
113
122
  # and line number, which should be unique. We hash it to make it a nice number
114
123
  key = caller.select { |p| p.include? ".html.erb" }[1]&.hash.to_s
115
- if @key.nil? || @key.empty?
116
- @key = key
117
- end
124
+ key += collection_key.to_s if collection_key
125
+ @key = key
126
+ end
118
127
 
128
+ def collection_key
129
+ nil
130
+ end
131
+
132
+ def permit_parameter?(initial_param, new_param)
133
+ initial_param != new_param
134
+ end
135
+
136
+ def omitted_from_state
137
+ []
138
+ end
139
+
140
+ def key
119
141
  # initialize session state
120
142
  if !stimulus_reflex? || session[@key].nil?
121
143
  new_state = {}
@@ -124,15 +146,19 @@ module ViewComponentReflex
124
146
  blacklist = [
125
147
  :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
126
148
  :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
127
- :@helpers, :@controller, :@request
149
+ :@helpers, :@controller, :@request, :@content
128
150
  ]
129
151
  instance_variables.reject { |k| blacklist.include?(k) }.each do |k|
130
- new_state[k] = instance_variable_get(k)
152
+ new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
131
153
  end
132
154
  ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
155
+ ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
133
156
  else
157
+ initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
134
158
  ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
135
- instance_variable_set(k, v)
159
+ unless permit_parameter?(initial_state[k], instance_variable_get(k))
160
+ instance_variable_set(k, v)
161
+ end
136
162
  end
137
163
  end
138
164
  @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.1'
2
+ VERSION = '1.4.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.1
4
+ version: 1.4.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-19 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