Class: ViewComponentReflex::Component

Inherits:
ViewComponent::Base
  • Object
show all
Defined in:
app/components/view_component_reflex/component.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.after_reflex(*args, &blk) ⇒ Object



44
45
46
# File 'app/components/view_component_reflex/component.rb', line 44

def after_reflex(*args, &blk)
  queue_callback(:after, args, blk)
end

.around_reflex(*args, &blk) ⇒ Object



48
49
50
# File 'app/components/view_component_reflex/component.rb', line 48

def around_reflex(*args, &blk)
  queue_callback(:around, args, blk)
end

.before_reflex(*args, &blk) ⇒ Object



40
41
42
# File 'app/components/view_component_reflex/component.rb', line 40

def before_reflex(*args, &blk)
  queue_callback(:before, args, blk)
end

.callbacks(key) ⇒ Object



29
30
31
32
# File 'app/components/view_component_reflex/component.rb', line 29

def callbacks(key)
  @callbacks ||= {}
  @callbacks[key] ||= []
end

.init_stimulus_reflexObject



4
5
6
7
8
# File 'app/components/view_component_reflex/component.rb', line 4

def init_stimulus_reflex
  factory = ViewComponentReflex::ReflexFactory.new(self)
  @stimulus_reflex ||= factory.reflex
  wire_up_callbacks if factory.new?
end

.queue_callback(key, args, blk) ⇒ Object



22
23
24
25
26
27
# File 'app/components/view_component_reflex/component.rb', line 22

def queue_callback(key, args, blk)
  callbacks(key).push({
    args: args,
    blk: blk
  })
end

.reflex_base_class(new_base_class = nil) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
# File 'app/components/view_component_reflex/component.rb', line 10

def reflex_base_class(new_base_class = nil)
  if new_base_class.nil?
    @reflex_base_class ||= ViewComponentReflex::Reflex
  else
    if new_base_class <= ViewComponentReflex::Reflex
      @reflex_base_class = new_base_class
    else
      raise StandardError.new("The reflex base class must inherit from ViewComponentReflex::Reflex")
    end
  end
end

.register_callbacks(key) ⇒ Object



34
35
36
37
38
# File 'app/components/view_component_reflex/component.rb', line 34

def register_callbacks(key)
  callbacks(key).each do |cb|
    @stimulus_reflex.send("#{key}_reflex", *cb[:args], &cb[:blk])
  end
end

.stimulus_controllerObject



59
60
61
# File 'app/components/view_component_reflex/component.rb', line 59

def self.stimulus_controller
  name.chomp("Component").underscore.dasherize
end

.wire_up_callbacksObject



52
53
54
55
56
# File 'app/components/view_component_reflex/component.rb', line 52

def wire_up_callbacks
  register_callbacks(:before)
  register_callbacks(:after)
  register_callbacks(:around)
end

Instance Method Details

#after_state_initialized(parameters_changed) ⇒ Object



142
143
144
# File 'app/components/view_component_reflex/component.rb', line 142

def after_state_initialized(parameters_changed)
  # called after state component has been hydrated
end

#can_render_to_string?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'app/components/view_component_reflex/component.rb', line 86

def can_render_to_string?
  omitted_from_state.empty?
end

#collection_keyObject



130
131
132
# File 'app/components/view_component_reflex/component.rb', line 130

def collection_key
  nil
end

#component_controller(opts_or_tag = :div, opts = {}, &blk) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'app/components/view_component_reflex/component.rb', line 67

def component_controller(opts_or_tag = :div, opts = {}, &blk)
  init_key

  tag = :div
  options = if opts_or_tag.is_a? Hash
    opts_or_tag
  else
    tag = opts_or_tag
    opts
  end

  options[:data] = {
    controller: self.class.stimulus_controller,
    key: key,
    **(options[:data] || {})
  }
   tag, capture(&blk), options
end

#init_keyObject

key is required if you’re using state We can’t initialize the session state in the initial method because it doesn’t have a view_context yet This is the next best place to do it



94
95
96
97
98
99
100
101
102
103
104
105
# File 'app/components/view_component_reflex/component.rb', line 94

def init_key
  # we want the erb file that renders the component. `caller` gives the file name,
  # and line number, which should be unique. We hash it to make it a nice number
  erb_file = caller.select { |p| p.match? /.\.html\.(haml|erb|slim)/ }[1]
  key = if erb_file
    Digest::SHA2.hexdigest(erb_file.split(":in")[0])
  else
    ""
  end
  key += collection_key.to_s if collection_key
  @key = key
end

#keyObject

def receive_params(old_state, params)

# no op

end



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'app/components/view_component_reflex/component.rb', line 150

def key
  # initialize session state
  if !stimulus_reflex? || ViewComponentReflex::Engine.state_adapter.state(request, @key).empty?

    new_state = create_safe_state

    ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
    ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
  elsif !@initialized_state
    initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")

    # incoming_params = safe_instance_variables.each_with_object({}) { |var, obj| obj[var] = instance_variable_get(var) }
    # receive_params(ViewComponentReflex::Engine.state_adapter.state(request, @key), incoming_params)

    parameters_changed = []
    ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
      instance_value = instance_variable_get(k)
      if permit_parameter?(initial_state[k], instance_value)
        parameters_changed << k
        ViewComponentReflex::Engine.state_adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
        ViewComponentReflex::Engine.state_adapter.set_state(request, controller, @key, {k => instance_value})
      else
        instance_variable_set(k, v)
      end
    end
    after_state_initialized(parameters_changed)
    @initialized_state = true
  end
  @key
end

#omitted_from_stateObject



138
139
140
# File 'app/components/view_component_reflex/component.rb', line 138

def omitted_from_state
  []
end

#permit_parameter?(initial_param, new_param) ⇒ Boolean

Returns:

  • (Boolean)


134
135
136
# File 'app/components/view_component_reflex/component.rb', line 134

def permit_parameter?(initial_param, new_param)
  initial_param != new_param
end

#reflex_data_attributes(reflex) ⇒ Object

Helper to use to create the proper reflex data attributes for an element



108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/components/view_component_reflex/component.rb', line 108

def reflex_data_attributes(reflex)
  action, method = reflex.to_s.split("->")
  if method.nil?
    method = action
    action = "click"
  end

  {
    reflex: "#{action}->#{self.class.name}##{method}",
    key: key
  }
end

#reflex_tag(reflex, name, content_or_options_with_block = {}, options = {}, escape = true, &block) ⇒ Object



121
122
123
124
125
126
127
128
# File 'app/components/view_component_reflex/component.rb', line 121

def reflex_tag(reflex, name, content_or_options_with_block = {}, options = {}, escape = true, &block)
  if content_or_options_with_block.is_a?(Hash)
    merge_data_attributes(content_or_options_with_block, reflex_data_attributes(reflex))
  else
    merge_data_attributes(options, reflex_data_attributes(reflex))
  end
  (name, content_or_options_with_block, options, escape, &block)
end

#safe_instance_variablesObject



181
182
183
# File 'app/components/view_component_reflex/component.rb', line 181

def safe_instance_variables
  instance_variables - unsafe_instance_variables
end

#stimulus_reflex?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'app/components/view_component_reflex/component.rb', line 63

def stimulus_reflex?
  helpers.controller.instance_variable_get(:@stimulus_reflex)
end