Class: Phlex::Reactive::Reply

Inherits:
Object
  • Object
show all
Defined in:
lib/phlex/reactive/reply.rb

Overview

A component-bound facade over Response — the surface an action body uses to control its reply. Component#reply returns one, so an action writes

reply.replace.flash(:error, msg)

instead of

Phlex::Reactive::Response.replace(self).flash(:error, msg)

Two warts disappear: there is no constant to qualify (reply is a method, resolved on the component — so a namespaced component needs no Response = … alias) and no self to thread (the component is bound).

Reply is NOT a Response and does NOT subclass one: each verb forwards to the Response class method, supplying the bound component as the subject, and returns the real, frozen Response value the endpoint already honors. So immutability, chaining (.flash/.stream/.also_update/.also_replace), and render_self? are inherited untouched — and there is no "verb after a chained Response" asymmetry, because the chain is plain Response all the way down.

Response remains the public value object (it's what the endpoint reads); it is simply an internal detail you rarely name directly now.

Instance Method Summary collapse

Constructor Details

#initialize(component) ⇒ Reply

Returns a new instance of Reply.



34
35
36
# File 'lib/phlex/reactive/reply.rb', line 34

def initialize(component)
  @component = component
end

Instance Method Details

#append(name, model) ⇒ Object

Reactive collections (issue #35) — add/remove a row in a declared reactive_collection, emitting the row stream + the count companion + the empty-state toggle as ONE Response. The bound component is the container (it carries the declaration + size resolver).

def add_item(...)    = (item = @list.items.create!(...); reply.append(:items, item))
def remove_item(id:) = (@list.items.find(id).destroy!;   reply.remove(:items, id))

model is the row's record; remove also accepts the row's dom-id string.



65
66
67
# File 'lib/phlex/reactive/reply.rb', line 65

def append(name, model)
  Response.collection_append(@component, name, model)
end

#morphObject

Re-render in place via Idiomorph (method="morph") — keeps focus + caret.



47
48
49
# File 'lib/phlex/reactive/reply.rb', line 47

def morph
  Response.morph(@component)
end

#prepend(name, model) ⇒ Object



69
70
71
# File 'lib/phlex/reactive/reply.rb', line 69

def prepend(name, model)
  Response.collection_prepend(@component, name, model)
end

#redirect(url) ⇒ Object

Client-side full navigation (Turbo.visit). Pass a *_url.



85
86
87
# File 'lib/phlex/reactive/reply.rb', line 85

def redirect(url)
  Response.redirect(url)
end

#remove(name = UNSET, model = UNSET) ⇒ Object

Two forms:

reply.remove               # remove the bound component's own element
reply.remove(:items, model) # remove a collection row + count + empty


76
77
78
79
80
# File 'lib/phlex/reactive/reply.rb', line 76

def remove(name = UNSET, model = UNSET)
  return Response.remove(@component) if name.equal?(UNSET)

  Response.collection_remove(@component, name, model)
end

#replace(morph: false) ⇒ Object

Re-render in place. morph: true morphs the subtree (preserves the focused input + caret) instead of an outerHTML swap — see #morph.



42
43
44
# File 'lib/phlex/reactive/reply.rb', line 42

def replace(morph: false)
  Response.replace(@component, morph:)
end

#streams(*strings) ⇒ Object

Self-targeting again: emit exactly these streams with a TOKEN-ONLY refresh (issue #30) — partial/per-field update, NO full-self replace, so the component's live inputs survive. The bound component supplies the token.



97
98
99
# File 'lib/phlex/reactive/reply.rb', line 97

def streams(*strings)
  Response.streams(@component, *strings)
end

#updateObject

Morph only inner HTML (preserves the root element + its token attr).



52
53
54
# File 'lib/phlex/reactive/reply.rb', line 52

def update
  Response.update(@component)
end

#with(*strings) ⇒ Object

Escape hatch / multi-stream root: zero or more raw turbo-stream strings.



90
91
92
# File 'lib/phlex/reactive/reply.rb', line 90

def with(*strings)
  Response.with(*strings)
end