Mercurial
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 |
| 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 } |