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

#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



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'app/components/view_component_reflex/component.rb', line 142

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)
  else
    initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
    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)
        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
  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



165
166
167
# File 'app/components/view_component_reflex/component.rb', line 165

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