annotate mrjunejune/src/public/mjj-composer.js @ 273:e02e2036ef84 default tip

add Layer 2 JRPG component system Add reusable content and window modals, an isolated component sandbox, shared cyberpunk scroll areas, production-safe cache freshness, and server-rendered JRPG panel state. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Sat, 08 Aug 2026 02:08:08 -0700
parents 41a49c29a28f
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
273
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
1 /**
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
2 * Layer 2 composer composite.
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
3 *
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
4 * Dependencies flow downward only: Zenbu Layer 1 primitives and Layer 0
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
5 * themes/i18n/API mapping. Application routes and state remain outside.
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
6 */
e02e2036ef84 add Layer 2 JRPG component system
MrJuneJune <me@mrjunejune.com>
parents: 272
diff changeset
7
272
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 * Coordinates a native composer form built from Zenbu controls.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 * @extends {HTMLElement}
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 export class MjjComposer extends HTMLElement {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 connectedCallback() {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 this._form = this.querySelector(":scope > form");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 this._textarea = this._form?.querySelector("textarea");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 this._submit = this._form?.querySelector('button[type="submit"]');
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 this._cancel = this._form?.querySelector("[data-composer-cancel]");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19 this._cancelOwner = this._form?.querySelector("[data-composer-cancel-owner]");
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 this._onSubmit = event => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 event.preventDefault();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 const message = this._textarea?.value.trim();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 if (!message || this._submit?.disabled) return;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 this.dispatchEvent(new CustomEvent("mjj-composer-submit", {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 bubbles: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 detail: { message },
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._form.reset();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 this._onKeydown = event => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 if (event.key !== "Enter" || event.shiftKey || event.isComposing) return;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32 event.preventDefault();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 this._form?.requestSubmit();
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 this._onCancel = () => {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 this.dispatchEvent(new CustomEvent("mjj-composer-cancel", {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37 bubbles: true,
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 }));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 };
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 this._form?.addEventListener("submit", this._onSubmit);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 this._textarea?.addEventListener("keydown", this._onKeydown);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 this._cancel?.addEventListener("click", this._onCancel);
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 disconnectedCallback() {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46 this._form?.removeEventListener("submit", this._onSubmit);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 this._textarea?.removeEventListener("keydown", this._onKeydown);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 this._cancel?.removeEventListener("click", this._onCancel);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 * Sets the active request state.
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 *
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 * @param {boolean} busy
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 setBusy(busy) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 if (this._textarea) this._textarea.disabled = busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 if (this._submit) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 this._submit.disabled = busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 this._submit.setAttribute("aria-busy", String(busy));
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 if (this._cancelOwner) this._cancelOwner.hidden = !busy;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64
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 * Shows or hides the cancellation action.
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 * @param {boolean} cancellable
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 setCancellable(cancellable) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71 if (this._cancelOwner) this._cancelOwner.hidden = !cancellable;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 /**
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75 * Enables or disables composer input.
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 * @param {boolean} disabled
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 */
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 setDisabled(disabled) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80 if (this._textarea) this._textarea.disabled = disabled;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
81 if (this._submit) this._submit.disabled = disabled;
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
82 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
83 }
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
84
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
85 if (!customElements.get("mjj-composer")) {
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
86 customElements.define("mjj-composer", MjjComposer);
41a49c29a28f polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
87 }