Mercurial
view mrjunejune/src/public/mjj-composer.js @ 272:41a49c29a28f
polish JRPG conversation experience
Integrate desktop conversations into the utility panel, simplify the mobile frame, add modal destinations and a reusable Zenbu composer lab, and preserve explicit conversation resume behavior.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 16:05:29 -0700 |
| parents | |
| children | e02e2036ef84 |
line wrap: on
line source
/** * Coordinates a native composer form built from Zenbu controls. * * @extends {HTMLElement} */ export class MjjComposer extends HTMLElement { connectedCallback() { this._form = this.querySelector(":scope > form"); this._textarea = this._form?.querySelector("textarea"); this._submit = this._form?.querySelector('button[type="submit"]'); this._cancel = this._form?.querySelector("[data-composer-cancel]"); this._cancelOwner = this._form?.querySelector("[data-composer-cancel-owner]"); this._onSubmit = event => { event.preventDefault(); const message = this._textarea?.value.trim(); if (!message || this._submit?.disabled) return; this.dispatchEvent(new CustomEvent("mjj-composer-submit", { bubbles: true, detail: { message }, })); this._form.reset(); }; this._onKeydown = event => { if (event.key !== "Enter" || event.shiftKey || event.isComposing) return; event.preventDefault(); this._form?.requestSubmit(); }; this._onCancel = () => { this.dispatchEvent(new CustomEvent("mjj-composer-cancel", { bubbles: true, })); }; this._form?.addEventListener("submit", this._onSubmit); this._textarea?.addEventListener("keydown", this._onKeydown); this._cancel?.addEventListener("click", this._onCancel); } disconnectedCallback() { this._form?.removeEventListener("submit", this._onSubmit); this._textarea?.removeEventListener("keydown", this._onKeydown); this._cancel?.removeEventListener("click", this._onCancel); } /** * Sets the active request state. * * @param {boolean} busy */ setBusy(busy) { if (this._textarea) this._textarea.disabled = busy; if (this._submit) { this._submit.disabled = busy; this._submit.setAttribute("aria-busy", String(busy)); } if (this._cancelOwner) this._cancelOwner.hidden = !busy; } /** * Shows or hides the cancellation action. * * @param {boolean} cancellable */ setCancellable(cancellable) { if (this._cancelOwner) this._cancelOwner.hidden = !cancellable; } /** * Enables or disables composer input. * * @param {boolean} disabled */ setDisabled(disabled) { if (this._textarea) this._textarea.disabled = disabled; if (this._submit) this._submit.disabled = disabled; } } if (!customElements.get("mjj-composer")) { customElements.define("mjj-composer", MjjComposer); }