view_component_reflex 1.7.2 → 2.1.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: 7e5577d7e345a14f59567739802588506a300b2caa96bba74bd4f12a93752a04
4
- data.tar.gz: be4d877d89d50555bde7f1ba929ef4fd5b1e60c72f2e7e921e33e2623574bfa7
3
+ metadata.gz: 46d3bc691137a986b26a9487624f004cf9625079040130a035129d12f3f52829
4
+ data.tar.gz: 9793628bd7618163d9c0014f887d8ef791ac25c2f168dd8c7cbb45e6c55f0839
5
5
  SHA512:
6
- metadata.gz: 60530d55c39126bd6be3d5be688f08cbe4e84e0b16e444334e438d99ec1a6b05a1f08c102407bea04b9c73ca5ace4bbb4ec013529810bc5363c6bd09e4224d70
7
- data.tar.gz: ceebff13ff2407be15ad1d3e851f78130a7bec2d00cdd260bd3ed78d32ebfce596f1763d6608b822d628f0ce91b164a53c47ee2296755733ddac01888ae1bf8c
6
+ metadata.gz: 014e4d807f719ccb361d9bd800ed599164c498c8e0a947820495982d63a1c07c7409041394d24e247701ec2510b27fe2bbfaee9829733946fe8e51ce630f8e80
7
+ data.tar.gz: 11cb4beef6ec931032d5b228fa43aee432ce8973fffa10c4391a8577d4788607937d3eb19b41650f778bbdd3cdad94f05e6eb69c0f97a7fdddc8056973f0152c
data/README.md CHANGED
@@ -108,6 +108,33 @@ def collection_key
108
108
  end
109
109
  ```
110
110
 
111
+ ### stimulate(target, data)
112
+ Stimulate another reflex from within your component. This typically requires the key of the component you're stimulating
113
+ which can be passed in via parameters.
114
+
115
+ ```ruby
116
+ def initialize(parent_key)
117
+ @parent_key = parent_key
118
+ end
119
+
120
+ def stimulate_other
121
+ stimulate("OtherComponent#method", { key: @parent_key })
122
+ end
123
+ ```
124
+
125
+ ### refresh!(selectors)
126
+ Refresh a specific element on the page. Using this will implicitly run `prevent_render!`.
127
+ If you want to render a specific element, as well as the component, a common pattern would be to pass `selector` as one of the parameters
128
+
129
+ ```
130
+ def my_method
131
+ refresh! '#my-special-element', selector
132
+ end
133
+ ```
134
+
135
+ ### selector
136
+ Returns the unique selector for this component. Useful to pass to `refresh!` when refreshing custom elements.
137
+
111
138
  ### prevent_refresh!
112
139
  By default, VCR will re-render your component after it executes your method. `revent_refresh!` prevents this from happening.
113
140
 
@@ -2,95 +2,12 @@ module ViewComponentReflex
2
2
  class Component < ViewComponent::Base
3
3
  class << self
4
4
  def init_stimulus_reflex
5
- klass = self
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)
8
- save_state
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
- "permanent_attribute_name" => "data-reflex-permanent"
17
- }
18
- end
19
-
20
- def refresh_all!
21
- refresh!("body")
22
- end
23
-
24
- # SR's delegate_call_to_reflex in channel.rb
25
- # uses method to gather the method parameters, but since we're abusing
26
- # method_missing here, that'll always fail
27
- def method(name)
28
- name.to_sym.to_proc
29
- end
30
-
31
- def respond_to_missing?(name, _ = false)
32
- !!name.to_proc
33
- end
34
-
35
- before_reflex do |a|
36
- a.send a.method_name
37
- throw :abort
38
- end
39
-
40
- def method_missing(name, *args)
41
- super unless respond_to_missing?(name)
42
- state.each do |k, v|
43
- component.instance_variable_set(k, v)
44
- end
45
- name.to_proc.call(component, *args)
46
- refresh! unless @prevent_refresh
47
- end
48
-
49
- def prevent_refresh!
50
- @prevent_refresh = true
51
- end
52
-
53
- define_method :component_class do
54
- @component_class ||= klass
55
- end
56
-
57
- private :component_class
58
-
59
- private
60
-
61
- def stimulus_controller
62
- component_class.stimulus_controller
63
- end
64
-
65
- def component
66
- return @component if @component
67
- @component = component_class.allocate
68
- reflex = self
69
- exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session, :prevent_refresh!]
70
- exposed_methods.each do |meth|
71
- @component.define_singleton_method(meth) do |*a|
72
- reflex.send(meth, *a)
73
- end
74
- end
75
- @component
76
- end
77
-
78
- def set_state(new_state = {})
79
- ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
80
- end
81
-
82
- def state
83
- ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
84
- end
85
-
86
- def save_state
87
- new_state = {}
88
- component.safe_instance_variables.each do |k|
89
- new_state[k] = component.instance_variable_get(k)
90
- end
91
- set_state(new_state)
92
- end
93
- })
5
+ if name.include? "::"
6
+ @stimulus_reflex ||= module_parent.const_set(name.split("::").last + "Reflex", Class.new(Reflex))
7
+ else
8
+ @stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(Reflex))
9
+ end
10
+ @stimulus_reflex.component_class = self
94
11
  end
95
12
  end
96
13
 
@@ -121,6 +38,10 @@ module ViewComponentReflex
121
38
  content_tag tag, capture(&blk), options
122
39
  end
123
40
 
41
+ def can_render_to_string?
42
+ omitted_from_state.empty?
43
+ end
44
+
124
45
  # key is required if you're using state
125
46
  # We can't initialize the session state in the initial method
126
47
  # because it doesn't have a view_context yet
@@ -174,7 +95,11 @@ module ViewComponentReflex
174
95
  else
175
96
  initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
176
97
  ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
177
- unless permit_parameter?(initial_state[k], instance_variable_get(k))
98
+ instance_value = instance_variable_get(k)
99
+ if permit_parameter?(initial_state[k], instance_value)
100
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, "#{@key}_initial", { k => instance_value })
101
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, @key, { k => instance_value })
102
+ else
178
103
  instance_variable_set(k, v)
179
104
  end
180
105
  end
@@ -192,7 +117,7 @@ module ViewComponentReflex
192
117
  [
193
118
  :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
194
119
  :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
195
- :@helpers, :@controller, :@request, :@content, :@tag_builder
120
+ :@helpers, :@controller, :@request, :@tag_builder
196
121
  ]
197
122
  end
198
123
 
@@ -0,0 +1,140 @@
1
+ module ViewComponentReflex
2
+ class Reflex < StimulusReflex::Reflex
3
+ include CableReady::Broadcaster
4
+
5
+ class << self
6
+ attr_accessor :component_class
7
+ end
8
+
9
+ def refresh!(primary_selector = nil, *rest)
10
+ save_state
11
+
12
+ if primary_selector.nil? && !component.can_render_to_string?
13
+ primary_selector = selector
14
+ end
15
+ if primary_selector
16
+ prevent_refresh!
17
+
18
+ controller.process(url_params[:action])
19
+ document = Nokogiri::HTML(controller.response.body)
20
+ [primary_selector, *rest].each do |s|
21
+ html = document.css(s)
22
+ if html.present?
23
+ cable_ready[channel.stream_name].morph(
24
+ selector: s,
25
+ html: html.inner_html,
26
+ children_only: true,
27
+ permanent_attribute_name: "data-reflex-permanent"
28
+ )
29
+ end
30
+ end
31
+ else
32
+ refresh_component!
33
+ end
34
+ cable_ready.broadcast
35
+ end
36
+
37
+ def refresh_component!
38
+ component.tap do |k|
39
+ k.define_singleton_method(:key) do
40
+ element.dataset[:key]
41
+ end
42
+ end
43
+ document = Nokogiri::HTML(controller.render_component_to_string(component))
44
+ cable_ready[channel.stream_name].morph(
45
+ selector: selector,
46
+ children_only: true,
47
+ html: document.css(selector).inner_html,
48
+ permanent_attribute_name: "data-reflex-permanent"
49
+ )
50
+ end
51
+
52
+ def refresh_all!
53
+ refresh!("body")
54
+ end
55
+
56
+ def selector
57
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
58
+ end
59
+
60
+ # SR's delegate_call_to_reflex in channel.rb
61
+ # uses method to gather the method parameters, but since we're abusing
62
+ # method_missing here, that'll always fail
63
+ def method(name)
64
+ name.to_sym.to_proc
65
+ end
66
+
67
+ def respond_to_missing?(name, _ = false)
68
+ !!name.to_proc
69
+ end
70
+
71
+ before_reflex do |a|
72
+ a.send a.method_name
73
+ throw :abort
74
+ end
75
+
76
+ def method_missing(name, *args)
77
+ super unless respond_to_missing?(name)
78
+ state.each do |k, v|
79
+ component.instance_variable_set(k, v)
80
+ end
81
+ name.to_proc.call(component, *args)
82
+ refresh! unless @prevent_refresh
83
+ end
84
+
85
+ def prevent_refresh!
86
+ @prevent_refresh = true
87
+ end
88
+
89
+ private
90
+
91
+ def component_class
92
+ self.class.component_class
93
+ end
94
+
95
+ def stimulus_controller
96
+ component_class.stimulus_controller
97
+ end
98
+
99
+ def stimulate(target, data)
100
+ dataset = {}
101
+ data.each do |k, v|
102
+ dataset["data-#{k}"] = v.to_s
103
+ end
104
+ channel.receive({
105
+ "target" => target,
106
+ "attrs" => element.attributes.to_h.symbolize_keys,
107
+ "dataset" => dataset
108
+ })
109
+ end
110
+
111
+ def component
112
+ return @component if @component
113
+ @component = component_class.allocate
114
+ reflex = self
115
+ exposed_methods = [:params, :request, :element, :refresh!, :refresh_all!, :stimulus_controller, :session, :prevent_refresh!, :selector, :stimulate]
116
+ exposed_methods.each do |meth|
117
+ @component.define_singleton_method(meth) do |*a|
118
+ reflex.send(meth, *a)
119
+ end
120
+ end
121
+ @component
122
+ end
123
+
124
+ def set_state(new_state = {})
125
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
126
+ end
127
+
128
+ def state
129
+ ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
130
+ end
131
+
132
+ def save_state
133
+ new_state = {}
134
+ component.safe_instance_variables.each do |k|
135
+ new_state[k] = component.instance_variable_get(k)
136
+ end
137
+ set_state(new_state)
138
+ end
139
+ end
140
+ end
@@ -1,7 +1,7 @@
1
1
  require "view_component_reflex/state_adapter/session"
2
2
  require "view_component_reflex/state_adapter/memory"
3
3
  require "view_component_reflex/engine"
4
- require 'stimulus_reflex'
4
+ require "stimulus_reflex"
5
5
 
6
6
  module ViewComponentReflex
7
7
  # Your code goes here...
@@ -1,3 +1,3 @@
1
1
  module ViewComponentReflex
2
- VERSION = '1.7.2'
2
+ VERSION = '2.1.1'
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.7.2
4
+ version: 2.1.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-07-06 00:00:00.000000000 Z
11
+ date: 2020-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -69,6 +69,7 @@ files:
69
69
  - README.md
70
70
  - Rakefile
71
71
  - app/components/view_component_reflex/component.rb
72
+ - app/reflexes/view_component_reflex/reflex.rb
72
73
  - lib/view_component_reflex.rb
73
74
  - lib/view_component_reflex/engine.rb
74
75
  - lib/view_component_reflex/state_adapter/memory.rb