| 1 | {{/* chat-panel — the suite's first chat panel (spec §6, §10): one |
| 2 | self-contained partial whose only companions are static/chat.js and |
| 3 | static/chat.css. It names nothing about Calls — no sqid, no room, no |
| 4 | room.js — so a second app adopts all three files unchanged: parse |
| 5 | this file, drop {{template "chat-panel" .}} where the panel belongs, |
| 6 | load the two assets, and call Chat.mount() with a send function. |
| 7 | |
| 8 | It takes no data. Everything it shows arrives through the mount |
| 9 | API at runtime, because chat is never stored and never replayed |
| 10 | (§6): the log starts empty on every load and goes with the tab. |
| 11 | |
| 12 | hidden is not decoration. The whole panel is script-only — a Send |
| 13 | button with no script behind it is a lie — so the server renders it |
| 14 | hidden and the script's host un-hides it when the panel is usable. |
| 15 | chat.css gives .chat a display of its own, so it carries the |
| 16 | matching .chat[hidden] rule; see the note at the top of that file. |
| 17 | |
| 18 | The control is the vendored field envelope written out rather than |
| 19 | called: ui's field-textarea has no Maxlength key, and §4.4's 2 KB |
| 20 | is the browser's own courtesy cap on a control the server will |
| 21 | refuse above it. Same attributes, same wiring — label bound with |
| 22 | for=, the status line named in aria-describedby so the two |
| 23 | sentences the panel can say reach a screen reader as part of the |
| 24 | field and not only as a live region. |
| 25 | |
| 26 | No `required`, deliberately. This form never reaches a server, so |
| 27 | the attribute would buy exactly one thing: the browser's own |
| 28 | validation bubble on an empty click of Send — a sentence in wording |
| 29 | and tone nobody here chose, and one this app's copy list could not |
| 30 | catalogue. Enter cannot raise that bubble anyway without routing |
| 31 | through requestSubmit(), so keeping it would leave the two ways of |
| 32 | sending behaving differently on an empty box. Without it both do |
| 33 | the same nothing, which is what every chat box does. */}} |
| 34 | {{define "chat-panel"}}<section id="chat" class="chat" data-chat aria-label="Chat" hidden> |
| 35 | <h2 class="chat-title">Chat</h2> |
| 36 | <ol id="chat-log" class="chat-log" data-chat-log aria-live="polite" aria-relevant="additions"></ol> |
| 37 | <form id="chat-form" class="chat-form" data-chat-form> |
| 38 | <label for="chat-text" class="chat-label">Message</label> |
| 39 | <textarea id="chat-text" name="text" rows="2" maxlength="2048" rst-input data-chat-text aria-describedby="chat-status"></textarea> |
| 40 | <button type="submit" id="chat-send" rst-btn data-chat-send>Send</button> |
| 41 | <p id="chat-status" class="chat-status" data-chat-status role="status"></p> |
| 42 | </form> |
| 43 | </section>{{end}} |
| 44 | |