{#- chirp-ui: Chat Input / Composer A working chat composer: auto-grow textarea, IME-safe Enter-to-send (send_key 'enter' | 'mod-enter'), a send/stop toggle bound to live upload + generation state, an optional attach control, and slots for attachment chips and suggestion chips. Server contract: form `hx-post`s the message; `stop_action` MUST be an endpoint that ABORTS the upstream generation task (not merely close the SSE listener). See docs/patterns/ai-chat.md. Usage: {% from "chirpui/chat_input.html" import composer %} {% call composer(action="/send", name="message", send_key="enter", stop_action="/abort", hx_target="#thread", hx_swap="beforeend") %} {% slot attachments %}{% end %} {% slot suggestions %}{% end %} {% end %} -#} {% def composer_send_stop(send_label="Send", stop_label="Stop", stop_action="", send_disabled_reason="Type a message or attach a file", hx_target=none) %} {% end %} {% def composer(action="", name="message", placeholder="Type a message...", rows=2, maxlength=none, send_key="enter", stop_action="", attach=false, send_label="Send", stop_label="Stop", send_disabled_reason="Type a message or attach a file", show_send_stop=true, hx=none, hx_post=none, hx_target=none, hx_swap=none, cls="") %} {% set _send_key = send_key | validate_variant(("enter", "mod-enter"), "enter") %} {% set _post = hx_post or action %} {% set _form_hx = build_hx_attrs(hx=hx, hx_post=_post, hx_target=hx_target, hx_swap=(hx_swap or "beforeend")) %}
{% end %} {# Back-compat: the old bare-form signature forwards to composer(). #} {% def chat_input(action="", name="message", placeholder="Type a message...", rows=2, maxlength=none, cls="") %} {% if caller is defined %} {% call composer(action=action, name=name, placeholder=placeholder, rows=rows, maxlength=maxlength, cls=cls, show_send_stop=false) %} {% slot footer %}{{ caller() }}{% end %} {% end %} {% else %} {% call composer(action=action, name=name, placeholder=placeholder, rows=rows, maxlength=maxlength, cls=cls) %} {% end %} {% end %} {% end %}