Class: Weft::Component
- Inherits:
-
Arbre::Component
- Object
- Arbre::Component
- Weft::Component
- Extended by:
- Registry::Eligibility
- Includes:
- Weft::Context::Interception, Weft::Context::Traversal, DSL::Actions, DSL::Containers, DSL::Inclusions, DSL::Params, DSL::Recoveries, DSL::Triggers, DSL::Updates
- Defined in:
- lib/weft/component.rb
Overview
Base class for all Weft components. Extends Arbre::Component with:
- Attribute DSL for declaring wire state
- Convention-based DOM ID and partial URL
- Auto-registration with the global Registry
Direct Known Subclasses
Constant Summary collapse
- SCALAR_ID_CLASSES =
Value classes whose instances may suffix a DOM id. An allowlist: arrays, hashes, and rich objects stringify to selector-hostile junk ("member-roster-[]" breaks querySelector), so only honest scalars ride.
[String, Symbol, Numeric, TrueClass, FalseClass].freeze
Class Attribute Summary collapse
-
.component_path ⇒ Object
Class-level path override (string or proc).
Attributes included from DSL::Params
Class Method Summary collapse
-
.inferred_routable? ⇒ Boolean
Inferred routability from declared state, ignoring any explicit override (see Weft::Registry::Eligibility#routable?).
- .inherited(subclass) ⇒ Object
-
.render(**wire_params) ⇒ Object
Render this component as an HTML string, outside any Arbre DSL context.
-
.resolved_component_path ⇒ Object
Resolves the actual path string for this component class.
-
.weft_dom_id_for(params = {}) ⇒ Object
Compute the would-be DOM ID for an instance of this class given a plain params hash, without instantiating.
Instance Method Summary collapse
- #build(attributes = {}) ⇒ Object
-
#initialize ⇒ Component
constructor
Params resolve at construction, not build: the context (which carries the wire source and any staged hand-off) is the constructor's one argument, and resolving here makes
paramsavailable even beforesuperin user build bodies — the "compute chrome from params, then super" pattern needs that. -
#weft_dom_id ⇒ Object
Convention-based DOM ID: dasherized class name + primary wire-param value.
-
#weft_url(**overrides) ⇒ Object
URL to this component's Weft route with current params as query string.
Methods included from Registry::Eligibility
abstract!, routable!, routable?
Methods included from Weft::Context::Interception
Methods included from Weft::Context::Traversal
#closest, #closest!, #enclosing, #enclosing!
Methods included from DSL::Containers
Methods included from DSL::Actions
Methods included from DSL::Updates
Methods included from DSL::Inclusions
Methods included from DSL::Triggers
Methods included from DSL::Recoveries
Methods included from DSL::Params
included, #serializable_params, warned_collisions
Constructor Details
#initialize ⇒ Component
Params resolve at construction, not build: the context (which carries
the wire source and any staged hand-off) is the constructor's one
argument, and resolving here makes params available even before
super in user build bodies — the "compute chrome from params, then
super" pattern needs that.
147 148 149 150 |
# File 'lib/weft/component.rb', line 147 def initialize(*) super @params = assembled_params end |
Class Attribute Details
.component_path ⇒ Object
Class-level path override (string or proc). Inherited by subclasses.
40 41 42 43 44 45 46 |
# File 'lib/weft/component.rb', line 40 def component_path if instance_variable_defined?(:@component_path) @component_path elsif superclass.respond_to?(:component_path) superclass.component_path end end |
Class Method Details
.inferred_routable? ⇒ Boolean
Inferred routability from declared state, ignoring any explicit override (see Weft::Registry::Eligibility#routable?). A component is independently addressable when it declares interactive behavior — params, actions, refresh triggers, or push config. Pure presentational components (none of those) register but are never served. Subclasses fall back to this when they have no override of their own, so an abstract parent does not disable concrete children.
68 69 70 |
# File 'lib/weft/component.rb', line 68 def inferred_routable? params.any? || actions.any? || refresh_triggers.any? || !push_config.nil? end |
.inherited(subclass) ⇒ Object
72 73 74 75 |
# File 'lib/weft/component.rb', line 72 def inherited(subclass) super Weft.registry.register(subclass) end |
.render(**wire_params) ⇒ Object
Render this component as an HTML string, outside any Arbre DSL context. The kwargs are pseudo-wire: exactly what a request's query string would carry. Used by the Router for partial responses, and available to users for testing, REPL exploration, or any standalone rendering need.
StatCard.render(status: "shipped") # => "<div id=\"...\">...</div>"
83 84 85 86 87 88 |
# File 'lib/weft/component.rb', line 83 def render(**wire_params) klass = self Weft::Context.new({}, nil, wire_params: wire_params) do insert_tag(klass) end.to_s end |
.resolved_component_path ⇒ Object
Resolves the actual path string for this component class. An explicit class-level override (string or proc) wins; otherwise the configured default proc derives one from the class name (see default_component_path).
53 54 55 56 57 58 59 |
# File 'lib/weft/component.rb', line 53 def resolved_component_path case (path = component_path) when Proc then path.call(self) when String then path else default_component_path end end |
.weft_dom_id_for(params = {}) ⇒ Object
Compute the would-be DOM ID for an instance of this class given a plain params hash, without instantiating. Single source of truth for the convention; the instance method delegates, and the Router falls back to this when it can't construct an instance to ask. The primary value suffixes only when it's a non-blank scalar — nil, "", and non-scalar values all derive the same bare class id, so a component's identity is stable across the ways "no value" arrives.
102 103 104 105 106 |
# File 'lib/weft/component.rb', line 102 def weft_dom_id_for(params = {}) base = name.underscore.tr("/", "-").tr("_", "-") primary_value = params.respond_to?(:values) ? params.values.first : nil identity_suffix?(primary_value) ? "#{base}-#{primary_value}" : base end |
Instance Method Details
#build(attributes = {}) ⇒ Object
152 153 154 155 156 157 158 159 160 |
# File 'lib/weft/component.rb', line 152 def build(attributes = {}) apply_received_fallback(attributes) unless arbre_context.respond_to?(:take_received!) warn_declared_chrome_collisions(attributes) super self.id = weft_dom_id claim_dom_slot! apply_refresh_attrs apply_push_attrs end |
#weft_dom_id ⇒ Object
Convention-based DOM ID: dasherized class name + primary wire-param value.
175 176 177 |
# File 'lib/weft/component.rb', line 175 def weft_dom_id self.class.weft_dom_id_for(serializable_params) end |
#weft_url(**overrides) ⇒ Object
URL to this component's Weft route with current params as query string. Pass overrides to change specific param values in the URL.
weft_url # => "/_components/orders_panel?status=shipped&page=1"
weft_url(page: 2) # => "/_components/orders_panel?status=shipped&page=2"
weft_url(status: nil, page: 1) # => "/_components/orders_panel?page=1"
168 169 170 171 172 |
# File 'lib/weft/component.rb', line 168 def weft_url(**overrides) path = self.class.resolved_component_path query = serializable_params.merge(overrides).compact query.empty? ? path : "#{path}?#{URI.encode_www_form(query)}" end |