From a0568ada5568bd8d6538e26e003b26c8409e2cb7 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 13 May 2025 18:14:04 -0400
Subject: Make the resulting form more amenable to normal DOM operations.

This is purely an aesthetic choice:

* The DOM `reset()` function can be used to clear the form, but can't be used to clear editable DIVs. Binding the editable div to a (hidden) form field allows `reset()` to clear both.

* We can find the target `form` element out of the event, but the API needed to do so differs between events dispatched to form controls and events dispatched to random DOM nodes. Using `closest('form')` works for both kinds of event target.

In practice, there is little need to make sure the message input form uses "normal" DOM APIs for functional reasons. Everything inside `MessageInput` is controllable through the component's script. This change isn't based on a functional need, but rather in the hopes that integrating with the DOM APIs makes it easier for _code we don't control_ - screen readers, password managers, saved-form support in browsers, &c - to integrate with Pilcrow. It is purely speculative.

(This also used to be necessary because Firefox didn't support `contenteditable="plaintext-only"`, but [support was added in March][ff-pto]

[ff-pto]: https://www.mozilla.org/en-US/firefox/136.0/releasenotes/#:~:text=The%20value%20plaintext%2Donly%20can%20now%20be%20specified%20for%20the%20contenteditable%20attribute%2C%20making%20the%20raw%20text%20of%20an%20element%20editable%20but%20without%20supporting%20rich%20text%20formatting.
---
 ui/lib/components/MessageInput.svelte | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'ui/lib/components/MessageInput.svelte')

diff --git a/ui/lib/components/MessageInput.svelte b/ui/lib/components/MessageInput.svelte
index 848321d..6c22b29 100644
--- a/ui/lib/components/MessageInput.svelte
+++ b/ui/lib/components/MessageInput.svelte
@@ -1,7 +1,6 @@
 <script>
   let { sendMessage = async (message) => {} } = $props();
 
-  let form = $state(null);
   let value = $state('');
   let disabled = $state(false);
 
@@ -10,7 +9,7 @@
     disabled = true;
     try {
       await sendMessage(value);
-      value = '';
+      event.target.closest('form')?.reset();
     } finally {
       disabled = false;
     }
@@ -25,7 +24,7 @@
     let modifier = event.shiftKey || event.altKey || event.ctrlKey || event.metaKey;
     if (!modifier && event.key === 'Enter') {
       event.preventDefault();
-      form?.requestSubmit?.();
+      event.target.closest('form')?.requestSubmit();
     }
   }
 
@@ -36,7 +35,8 @@
   }
 </script>
 
-<form {onsubmit} bind:this={form}>
+<form {onsubmit}>
+  <textarea bind:value class="hidden" {disabled}></textarea>
   <div
     contenteditable="plaintext-only"
     class={{
-- 
cgit v1.2.3

