Module: Vident2::Component
- Extended by:
- ActiveSupport::Concern
- Includes:
- Tailwind
- Included in:
- Phlex::HTML, ViewComponent::Base
- Defined in:
- lib/vident2/component.rb
Overview
Composition root for Vident 2.0 components: props, DSL receiver, singular/plural parsers, add_stimulus_* mutators, and the render pipeline glue.
Constant Summary collapse
- SINGULAR_PARSERS =
Singular parsers return a pre-built value object; pre-built input passes through unchanged.
{ controllers: :stimulus_controller, actions: :stimulus_action, targets: :stimulus_target, outlets: :stimulus_outlet, values: :stimulus_value, params: :stimulus_param, class_maps: :stimulus_class }.freeze
- PLURAL_PARSERS =
Plural parsers return a Collection (exposes ‘#to_h` for `data:` splatting). Inputs: Symbol / String / Array (= singular parser’s arg tuple) / Hash (keyed: one pair each) / pre-built Value or Collection (pass-through).
{ controllers: :stimulus_controllers, actions: :stimulus_actions, targets: :stimulus_targets, outlets: :stimulus_outlets, values: :stimulus_values, params: :stimulus_params, class_maps: :stimulus_classes }.freeze
- MUTATOR_METHODS =
Mutators. One call = one entry: Array input is the singular parser’s arg tuple, NOT splatted across multiple mutator calls.
{ controllers: :add_stimulus_controllers, actions: :add_stimulus_actions, targets: :add_stimulus_targets, outlets: :add_stimulus_outlets, values: :add_stimulus_values, params: :add_stimulus_params, class_maps: :add_stimulus_classes }.freeze
- SINGULAR_NAMES =
Kind name → ‘stimulus_<singular>` suffix (used by child_element).
{ controllers: :controller, actions: :action, targets: :target, outlets: :outlet, values: :value, params: :param, class_maps: :class }.freeze
Instance Method Summary collapse
-
#after_component_initialize ⇒ Object
User hook: runs after the Draft is built but before seal.
-
#child_element(tag_name, stimulus_controllers: nil, stimulus_targets: nil, stimulus_actions: nil, stimulus_outlets: nil, stimulus_values: nil, stimulus_params: nil, stimulus_classes: nil, stimulus_controller: nil, stimulus_target: nil, stimulus_action: nil, stimulus_outlet: nil, stimulus_value: nil, stimulus_param: nil, stimulus_class: nil, **options, &block) ⇒ Object
Emit a child element with stimulus_* kwargs folded into data-* attrs.
-
#class_list_for_stimulus_classes(*names) ⇒ Object
SSR helper: resolved ClassMap entries matching ‘names` as a space-joined String.
-
#clone(overrides = {}) ⇒ Object
Fresh instance with current props merged with overrides.
- #component_name ⇒ Object
-
#generate_child_element(tag_name, stimulus_data_attributes, options, &block) ⇒ Object
tag guard.
-
#id ⇒ Object
Auto-id: ‘<component-name>-<stable-id>`.
-
#inspect(klass_name = "Component") ⇒ Object
Custom format kept for tooling / specs that regex-match output.
-
#outlet_id ⇒ Object
Stable ‘[identifier, “#<id>”]` pair for connecting an outlet to this instance.
- #prop_names ⇒ Object
-
#random_id ⇒ Object
Auto-generated id, independent of the ‘id:` prop.
-
#resolve_stimulus_attributes_at_render_time ⇒ Object
Resolve DSL proc entries deferred at ‘after_initialize`.
-
#root ⇒ Object
Dispatches to the adapter-specific ‘root_element` on subclasses (Phlex / ViewComponent).
- #root_element(**overrides, &block) ⇒ Object
-
#root_element_attributes ⇒ Object
User override: extra attrs for the root.
-
#root_element_classes ⇒ Object
User override: instance-level extra classes for the root (one tier of ClassListBuilder’s cascade).
- #stimulus_identifier ⇒ Object
- #stimulus_scoped_event(event) ⇒ Object
- #stimulus_scoped_event_on_window(event) ⇒ Object
Methods included from Tailwind
#tailwind_merge_available?, #tailwind_merger
Instance Method Details
#after_component_initialize ⇒ Object
User hook: runs after the Draft is built but before seal.
202 203 |
# File 'lib/vident2/component.rb', line 202 def after_component_initialize end |
#child_element(tag_name, stimulus_controllers: nil, stimulus_targets: nil, stimulus_actions: nil, stimulus_outlets: nil, stimulus_values: nil, stimulus_params: nil, stimulus_classes: nil, stimulus_controller: nil, stimulus_target: nil, stimulus_action: nil, stimulus_outlet: nil, stimulus_value: nil, stimulus_param: nil, stimulus_class: nil, **options, &block) ⇒ Object
Emit a child element with stimulus_* kwargs folded into data-* attrs. Plural kwargs must be Enumerable. Adapter provides the tag emission (‘generate_child_element`).
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/vident2/component.rb', line 320 def child_element( tag_name, stimulus_controllers: nil, stimulus_targets: nil, stimulus_actions: nil, stimulus_outlets: nil, stimulus_values: nil, stimulus_params: nil, stimulus_classes: nil, stimulus_controller: nil, stimulus_target: nil, stimulus_action: nil, stimulus_outlet: nil, stimulus_value: nil, stimulus_param: nil, stimulus_class: nil, **, &block ) inputs = { controllers: [stimulus_controllers, stimulus_controller], actions: [stimulus_actions, stimulus_action], targets: [stimulus_targets, stimulus_target], outlets: [stimulus_outlets, stimulus_outlet], values: [stimulus_values, stimulus_value], params: [stimulus_params, stimulus_param], class_maps: [stimulus_classes, stimulus_class] } data_attrs = {} ::Vident2::Internals::Registry.each do |kind| plural, singular = inputs.fetch(kind.name) child_element_check_plural!(plural, singular, kind) coll = child_element_build_collection(kind, plural, singular) data_attrs.merge!(coll.to_h) unless coll.empty? end generate_child_element(tag_name, data_attrs, , &block) end |
#class_list_for_stimulus_classes(*names) ⇒ Object
SSR helper: resolved ClassMap entries matching ‘names` as a space-joined String. Tailwind-merged if available. `“”` on miss.
303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/vident2/component.rb', line 303 def class_list_for_stimulus_classes(*names) resolve_stimulus_attributes_at_render_time plan = seal_draft maps = plan.class_maps return "" if maps.empty? || names.empty? result = ::Vident2::Internals::ClassListBuilder.call( stimulus_classes: maps, stimulus_class_names: names, tailwind_merger: tailwind_merger ) result || "" end |
#clone(overrides = {}) ⇒ Object
Fresh instance with current props merged with overrides.
173 174 175 |
# File 'lib/vident2/component.rb', line 173 def clone(overrides = {}) self.class.new(**to_h.merge(overrides)) end |
#component_name ⇒ Object
146 |
# File 'lib/vident2/component.rb', line 146 def component_name = self.class.component_name |
#generate_child_element(tag_name, stimulus_data_attributes, options, &block) ⇒ Object
tag guard. VC: content_tag / tag.
534 535 536 |
# File 'lib/vident2/component.rb', line 534 def generate_child_element(tag_name, stimulus_data_attributes, , &block) raise NoMethodError, "adapter must implement generate_child_element" end |
#id ⇒ Object
Auto-id: ‘<component-name>-<stable-id>`. `.presence` is intentional — blank string falls through to auto-generation.
156 157 158 |
# File 'lib/vident2/component.rb', line 156 def id @id.presence || random_id end |
#inspect(klass_name = "Component") ⇒ Object
Custom format kept for tooling / specs that regex-match output.
178 179 180 181 |
# File 'lib/vident2/component.rb', line 178 def inspect(klass_name = "Component") attr_text = to_h.map { |k, v| "#{k}=#{v.inspect}" }.join(", ") "#<#{self.class.name}<Vident::#{klass_name}> #{attr_text}>" end |
#outlet_id ⇒ Object
Stable ‘[identifier, “#<id>”]` pair for connecting an outlet to this instance.
168 169 170 |
# File 'lib/vident2/component.rb', line 168 def outlet_id @outlet_id ||= [stimulus_identifier, "##{id}"] end |
#prop_names ⇒ Object
145 |
# File 'lib/vident2/component.rb', line 145 def prop_names = self.class.prop_names |
#random_id ⇒ Object
Auto-generated id, independent of the ‘id:` prop. Useful for ARIA references that need to be stable per-instance.
162 163 164 |
# File 'lib/vident2/component.rb', line 162 def random_id @__vident2_auto_id ||= "#{component_name}-#{::Vident2::StableId.next_id_in_sequence}" end |
#resolve_stimulus_attributes_at_render_time ⇒ Object
Resolve DSL proc entries deferred at ‘after_initialize`. Called by the adapter’s ‘before_template` / `before_render`; `seal_draft` and `class_list_for_stimulus_classes` call it as safety nets.
Flag set before the guards so a sealed Draft can’t trap us in a loop where every subsequent call re-takes the sealed branch.
381 382 383 384 385 386 387 388 389 |
# File 'lib/vident2/component.rb', line 381 def resolve_stimulus_attributes_at_render_time return if @__vident2_procs_resolved @__vident2_procs_resolved = true # Nil = test double. Sealed = someone consumed the Draft already. return if @__vident2_draft.nil? || @__vident2_draft.sealed? ::Vident2::Internals::Resolver.resolve_procs_into( @__vident2_draft, self.class.declarations, self ) end |
#root ⇒ Object
Dispatches to the adapter-specific ‘root_element` on subclasses (Phlex / ViewComponent). Keep as `def` not `alias_method` so Ruby’s dynamic dispatch finds the subclass override.
528 529 530 |
# File 'lib/vident2/component.rb', line 528 def root(...) root_element(...) end |
#root_element(**overrides, &block) ⇒ Object
521 522 523 |
# File 'lib/vident2/component.rb', line 521 def root_element(**overrides, &block) raise NoMethodError, "subclass must implement root_element" end |
#root_element_attributes ⇒ Object
User override: extra attrs for the root. ‘stimulus_*:` keys APPEND into the Draft (same as props).
193 |
# File 'lib/vident2/component.rb', line 193 def root_element_attributes = {} |
#root_element_classes ⇒ Object
User override: instance-level extra classes for the root (one tier of ClassListBuilder’s cascade). Return nil for no contribution.
197 198 199 |
# File 'lib/vident2/component.rb', line 197 def root_element_classes nil end |
#stimulus_identifier ⇒ Object
147 |
# File 'lib/vident2/component.rb', line 147 def stimulus_identifier = self.class.stimulus_identifier |
#stimulus_scoped_event(event) ⇒ Object
151 |
# File 'lib/vident2/component.rb', line 151 def stimulus_scoped_event(event) = self.class.stimulus_scoped_event(event) |
#stimulus_scoped_event_on_window(event) ⇒ Object
152 |
# File 'lib/vident2/component.rb', line 152 def stimulus_scoped_event_on_window(event) = self.class.stimulus_scoped_event_on_window(event) |