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



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

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

.around_reflex(*args, &blk) ⇒ Object



38
39
40
# File 'app/components/view_component_reflex/component.rb', line 38

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

.before_reflex(*args, &blk) ⇒ Object



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

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

.callbacks(key) ⇒ Object



19
20
21
22
# File 'app/components/view_component_reflex/component.rb', line 19

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

.init_stimulus_reflexObject



6
7
8
9
10
# File 'app/components/view_component_reflex/component.rb', line 6

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



12
13
14
15
16
17
# File 'app/components/view_component_reflex/component.rb', line 12

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

.register_callbacks(key) ⇒ Object



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

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

.stimulus_controllerObject



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

def self.stimulus_controller
  name.chomp("Component").underscore.dasherize.gsub("/", "--")
end

.wire_up_callbacksObject



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

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

Instance Method Details

#after_state_initialized(parameters_changed) ⇒ Object



132
133
134
# File 'app/components/view_component_reflex/component.rb', line 132

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

#can_render_to_string?Boolean

Returns:

  • (Boolean)


76
77
78
# File 'app/components/view_component_reflex/component.rb', line 76

def can_render_to_string?
  omitted_from_state.empty?
end

#collection_keyObject



120
121
122
# File 'app/components/view_component_reflex/component.rb', line 120

def collection_key
  nil
end

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



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/components/view_component_reflex/component.rb', line 57

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



84
85
86
87
88
89
90
91
92
93
94
95
# File 'app/components/view_component_reflex/component.rb', line 84

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



140
141
142
143
144
145
146
147
148
149
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
# File 'app/components/view_component_reflex/component.rb', line 140

def key
  adapter = ViewComponentReflex::Engine.state_adapter

  # initialize session state
  if (!stimulus_reflex? || adapter.state(request, @key).empty?) && !@initialized_state

    new_state = create_safe_state

    adapter.wrap_write_async do
      adapter.store_state(request, @key, new_state)
      adapter.store_state(request, "#{@key}_initial", new_state)
    end
  elsif !@initialized_state
    initial_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 = []
    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
        adapter.wrap_write_async do
          adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
          adapter.set_state(request, controller, @key, {k => instance_value})
        end
      else
        instance_variable_set(k, v)
      end
    end
    after_state_initialized(parameters_changed)
  end

  @initialized_state = true
  @key
end

#omitted_from_stateObject



128
129
130
# File 'app/components/view_component_reflex/component.rb', line 128

def omitted_from_state
  []
end

#permit_parameter?(initial_param, new_param) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
# File 'app/components/view_component_reflex/component.rb', line 124

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



98
99
100
101
102
103
104
105
106
107
108
109
# File 'app/components/view_component_reflex/component.rb', line 98

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



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

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



178
179
180
# File 'app/components/view_component_reflex/component.rb', line 178

def safe_instance_variables
  instance_variables - unsafe_instance_variables - omitted_from_state
end

#stimulus_reflex?Boolean

Returns:

  • (Boolean)


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

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