view_component_reflex 0.2.2 → 0.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: 496ca8914c7e26b3cf8d6e8023e3919f554354e81c6b67900290c1872fee518a
4
- data.tar.gz: 322663d7019f05aa3065b6cc619c37c0f26e94a1e39bb6a42731fa46e48bc61d
3
+ metadata.gz: 6604db3319eb30b4cf0ac65502e46c3c1107094290b7ba2c9efda8c16735b250
4
+ data.tar.gz: d644b0e76cc36cd6f969406569c4f28d32719e574a848bc360db0979398a0dbc
5
5
  SHA512:
6
- metadata.gz: f4aff8020d47d29c6e1c4a44ff6819178ac5fd6767785009a8d91e87d856b170a452796e636da127a4c91ab7e07de64805826175d28b966d5002f8da0d275d45
7
- data.tar.gz: 88f1b3feb877862866846f2d599f846308c5281d7e8feff60de4acbea3300613e4baebf84191cad43cf9ead7a7005efda74af874eea8e34dc15a7aa4887a5811
6
+ metadata.gz: 3af567ec00951af7ba672cee153b30971f0c9ec679c148447c4e2379687e1af7592d3c23960135a9efd8d1d752bb9f482bcafd83731a88d60f6740175acce586
7
+ data.tar.gz: a4a16cf03448c3251dd94714a98f269e06c983a7f1351aab7622a65a80a9ef3794c277fbd0cbb4b2ba7de91c16e4de4f4c4eff49dee4afa2f3a605d56980b14c
data/README.md CHANGED
@@ -19,7 +19,8 @@ using stimulus reflex.
19
19
 
20
20
  In addition to calling reflexes, there is a rudimentary state system. You can initialize component-local state with `initialize_state(obj)`, where `obj` is a hash.
21
21
 
22
- You can access state with the `state` helper. See the code below for an example.
22
+ You can access state with the `state` helper. See the code below for an example. Calling `set_state` will set the state,
23
+ and also re-render your component.
23
24
 
24
25
  If you're using state add `data-key="<%= key %>"` to any html element using a reflex. This
25
26
  lets ViewComponentReflex keep track of which state belongs to which component.
@@ -36,7 +37,7 @@ lets ViewComponentReflex keep track of which state belongs to which component.
36
37
  end
37
38
 
38
39
  reflex :increment do
39
- state[:count] = state[:count] + 1
40
+ set_state(count: state[:count] + 1)
40
41
  end
41
42
  end
42
43
  ```
@@ -49,6 +50,64 @@ lets ViewComponentReflex keep track of which state belongs to which component.
49
50
  </div>
50
51
  ```
51
52
 
53
+ ## Custom State Adapters
54
+
55
+ ViewComponentReflex uses session for its state by default. To change this, add
56
+ an initializer to `config/initializers/view_component_reflex.rb`.
57
+
58
+ ```ruby
59
+ ViewComponentReflex.configure do |config|
60
+ config.state_adapter = YourAdapter
61
+ end
62
+ ```
63
+
64
+ `YourAdapter` should implement
65
+
66
+ ```ruby
67
+ class YourAdapter
68
+ ##
69
+ # request - a rails request object
70
+ # key - a unique string that identifies the component instance
71
+ def self.state(request, key)
72
+ # Return state for a given key
73
+ end
74
+
75
+ ##
76
+ # reflex - The reflex instance that's trying to set the state
77
+ # key - a unique string that identifies the component
78
+ # new_state - the new state to set
79
+ def self.set_state(reflex, key, new_state)
80
+ end
81
+
82
+
83
+ ##
84
+ # request - a rails request object
85
+ # key - a unique string that identifies the component instance
86
+ # new_state - a hash containing the component state
87
+ def self.store_state(request, key, new_state = {})
88
+ # store the state
89
+ # this will be called twice, once with key, once with key_initial
90
+ # key_initial contains the initial, unmodified state.
91
+ # it should be used in reconcile_state to decide whether or not
92
+ # to re-initialize the state
93
+ end
94
+
95
+ ##
96
+ # request - a rails request object
97
+ # key - a unique string that identifies the component instance
98
+ # new_state - a hash containing the component state
99
+ def self.reconcile_state(request, key, new_state)
100
+ # The passed state should always match the initial state of the component
101
+ # if it doesn't, we need to reset the state to the passed value.
102
+ #
103
+ # This handles cases where your initialize_state param computes some value that changes
104
+ # initialize_state({ transaction: @customer.transactions.first })
105
+ # if you delete the first transaction, that ^ is no longer valid. We need to update the state.
106
+ end
107
+ end
108
+ ```
109
+
110
+
52
111
  ## Installation
53
112
  Add this line to your application's Gemfile:
54
113
 
@@ -9,7 +9,29 @@ module ViewComponentReflex
9
9
  klass = self
10
10
  @stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(StimulusReflex::Reflex) {
11
11
  def state
12
- session[element.dataset[:key]] ||= {}
12
+ ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
13
+ end
14
+
15
+ def set_state(new_state)
16
+ ViewComponentReflex::Engine.state_adapter.set_state(self, element.dataset[:key], new_state)
17
+ @channel.render_page_and_broadcast_morph(self, nil, {
18
+ dataset: element.dataset.to_h,
19
+ args: [],
20
+ attrs: element.attributes.to_h,
21
+ selectors: ['body'],
22
+ target: "#{self.class.name}##{method_name}",
23
+ url: request.url,
24
+ permanentAttributeName: "data-reflex-permanent"
25
+ })
26
+ end
27
+
28
+ before_reflex do |reflex, *args|
29
+ instance_exec(*args, &self.class.callbacks[self.method_name.to_sym]) if self.class.callbacks.include?(self.method_name.to_sym)
30
+ throw :abort
31
+ end
32
+
33
+ def self.callbacks
34
+ @callbacks ||= {}
13
35
  end
14
36
 
15
37
  define_method :stimulus_controller do
@@ -17,8 +39,8 @@ module ViewComponentReflex
17
39
  end
18
40
 
19
41
  define_singleton_method(:reflex) do |name, &blk|
42
+ callbacks[name] = blk
20
43
  define_method(name) do |*args|
21
- instance_exec(*args, &blk)
22
44
  end
23
45
  end
24
46
  })
@@ -30,7 +52,7 @@ module ViewComponentReflex
30
52
  end
31
53
 
32
54
  # key is required if you're using state
33
- # We can't initialize the session state in the initiale method
55
+ # We can't initialize the session state in the initial method
34
56
  # because it doesn't have a view_context yet
35
57
  # This is the next best place to do it
36
58
  def key
@@ -38,16 +60,16 @@ module ViewComponentReflex
38
60
 
39
61
  # initialize session state
40
62
  if session[@key].nil?
41
- session[@key] = {}
42
- (@state ||= {}).each do |key, v|
43
- session[@key][key] = v
44
- end
63
+ ViewComponentReflex::Engine.state_adapter.store_state(request, @key, @state)
64
+ ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", @state)
65
+ else
66
+ ViewComponentReflex::Engine.state_adapter.reconcile_state(request, @key, @state)
45
67
  end
46
68
  @key
47
69
  end
48
70
 
49
71
  def state
50
- session[key]
72
+ ViewComponentReflex::Engine.state_adapter.state(request, key)
51
73
  end
52
74
  end
53
75
  end
@@ -1,18 +1,7 @@
1
+ require "view_component_reflex/state_adapter/session"
1
2
  require "view_component_reflex/engine"
2
3
  require 'stimulus_reflex'
3
4
 
4
5
  module ViewComponentReflex
5
6
  # Your code goes here...
6
7
  end
7
-
8
- module StimulusReflexChannelExtension
9
- def render_page_and_broadcast_morph(reflex, selectors, data = {})
10
- html = render_page(reflex)
11
- if reflex.respond_to? :stimulus_controller
12
- selectors = ["[data-controller=\"#{reflex.stimulus_controller}\"]"]
13
- end
14
- broadcast_morphs selectors, data, html if html.present?
15
- end
16
- end
17
-
18
- StimulusReflex::Channel.include StimulusReflexChannelExtension
@@ -1,4 +1,26 @@
1
1
  module ViewComponentReflex
2
2
  class Engine < ::Rails::Engine
3
+ class << self
4
+ mattr_accessor :state_adapter
5
+
6
+ self.state_adapter = StateAdapter::Session
7
+ end
8
+
9
+ def self.configure
10
+ yield self if block_given?
11
+ end
12
+
13
+ config.to_prepare do
14
+ class StimulusReflex::Channel < ActionCable::Channel::Base
15
+ def render_page_and_broadcast_morph(reflex, selectors, data = {})
16
+ html = render_page(reflex)
17
+ if reflex.respond_to? :stimulus_controller
18
+ selectors = ["[data-controller=\"#{reflex.stimulus_controller}\"]"]
19
+ end
20
+ broadcast_morphs selectors, data, html if html.present?
21
+ end
22
+ end
23
+
24
+ end
3
25
  end
4
26
  end
@@ -0,0 +1,38 @@
1
+ module ViewComponentReflex
2
+ module StateAdapter
3
+ class Session
4
+ def self.state(request, key)
5
+ request.session[key] ||= {}
6
+ end
7
+
8
+ def self.set_state(reflex, key, new_state)
9
+ new_state.each do |k, v|
10
+ state(reflex.request, key)[k] = v
11
+ end
12
+ store = reflex.request.session.instance_variable_get("@by")
13
+ store.commit_session reflex.request, reflex.controller.response
14
+ end
15
+
16
+ def self.store_state(request, key, new_state = {})
17
+ request.session[key] = {}
18
+ new_state.each do |k, v|
19
+ request.session[key][k] = v
20
+ end
21
+ end
22
+
23
+ # The passed state should always match the initial state of the component
24
+ # if it doesn't, we need to reset the state to the passed value.
25
+ #
26
+ # This handles cases where your initialize_state param computes some value that changes
27
+ # initialize_state({ transaction: @customer.transactions.first })
28
+ # if you delete the first transaction, that ^ is no longer valid. We need to update the state.
29
+ def self.reconcile_state(request, key, new_state)
30
+ request.session["#{key}_initial"].each do |k, v|
31
+ if new_state[k] != v
32
+ request.session[key][k] = new_state[k]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module ViewComponentReflex
2
- VERSION = '0.2.2'
2
+ VERSION = '0.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: 0.2.2
4
+ version: 0.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-04 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -71,6 +71,7 @@ files:
71
71
  - app/components/view_component_reflex/component.rb
72
72
  - lib/view_component_reflex.rb
73
73
  - lib/view_component_reflex/engine.rb
74
+ - lib/view_component_reflex/state_adapter/session.rb
74
75
  - lib/view_component_reflex/version.rb
75
76
  homepage: https://github.com/joshleblanc/view_component_reflex
76
77
  licenses: