annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2 * Coordinates a native composer form built from Zenbu controls.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4 * @extends {HTMLElement}
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 export class MjjComposer extends HTMLElement {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7 connectedCallback() {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 this._form = this.querySelector(":scope > form");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 this._textarea = this._form?.querySelector("textarea");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 this._submit = this._form?.querySelector('button[type="submit"]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 this._cancel = this._form?.querySelector("[data-composer-cancel]");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 this._cancelOwner = this._form?.querySelector("[data-composer-cancel-owner]");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 this._onSubmit = event => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 event.preventDefault();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 const message = this._textarea?.value.trim();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 if (!message || this._submit?.disabled) return;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 this.dispatchEvent(new CustomEvent("mjj-composer-submit", {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 bubbles: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19 detail: { message },
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 }));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 this._form.reset();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 this._onKeydown = event => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 if (event.key !== "Enter" || event.shiftKey || event.isComposing) return;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 event.preventDefault();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 this._form?.requestSubmit();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 this._onCancel = () => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 this.dispatchEvent(new CustomEvent("mjj-composer-cancel", {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 bubbles: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 }));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 this._form?.addEventListener("submit", this._onSubmit);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 this._textarea?.addEventListener("keydown", this._onKeydown);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 this._cancel?.addEventListener("click", this._onCancel);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 disconnectedCallback() {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 this._form?.removeEventListener("submit", this._onSubmit);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 this._textarea?.removeEventListener("keydown", this._onKeydown);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 this._cancel?.removeEventListener("click", this._onCancel);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 * Sets the active request state.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 * @param {boolean} busy
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 setBusy(busy) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 if (this._textarea) this._textarea.disabled = busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 if (this._submit) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 this._submit.disabled = busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 this._submit.setAttribute("aria-busy", String(busy));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 if (this._cancelOwner) this._cancelOwner.hidden = !busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 * Shows or hides the cancellation action.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 * @param {boolean} cancellable
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 setCancellable(cancellable) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64 if (this._cancelOwner) this._cancelOwner.hidden = !cancellable;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 * Enables or disables composer input.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 * @param {boolean} disabled
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 setDisabled(disabled) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73 if (this._textarea) this._textarea.disabled = disabled;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 if (this._submit) this._submit.disabled = disabled;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
76 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
77
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 if (!customElements.get("mjj-composer")) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 customElements.define("mjj-composer", MjjComposer);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80 }