From ff3d042c0e7e63ab3d32db973b638f4296b0a6e4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 23:11:38 +0000 Subject: [PATCH] =?UTF-8?q?Workers=20P4=20Endpr=C3=BCfung=20W4:=20Esc=20un?= =?UTF-8?q?d=20=E2=80=9EAbbrechen=E2=80=9C=20schlie=C3=9Fen=20die=20Felder?= =?UTF-8?q?=20und=20geben=20den=20Fokus=20an=20den=20Knopf=20zur=C3=BCck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit „Als Mensch antworten“ und „Antwort des Kunden einfügen“ ließen sich nur durch erneuten Klick auf den Auslöser schließen. Esc (aus dem ganzen Feld, mit preventDefault für die Handy-Leiste) und der neue Knopf „Abbrechen“ schließen das Feld, der Text bleibt in der Liste erhalten, der Fokus geht an den Auslöser zurück (data-opens am Knopf, gesucht in der Aktionsgruppe: Button reicht kein ref durch). Während einer Anfrage sind beide gesperrt. Neue Gruppe .wk-pult-panel-btns, auf dem Handy mit dem Hauptknopf oben. Test-Läufer: ref-Objekte an Tags und eine document-Attrappe für den Fokus. Co-Authored-By: Claude Sonnet 5.5 --- scripts/workers-harness/shot.cjs | 4 +- src/components/workers/PultList.jsx | 35 +++++++-- src/styles/workers.css | 4 + tests/unit/workersPultUi.test.mjs | 109 +++++++++++++++++++++++++++- 4 files changed, 141 insertions(+), 11 deletions(-) diff --git a/scripts/workers-harness/shot.cjs b/scripts/workers-harness/shot.cjs index 42f9e8b..516c377 100644 --- a/scripts/workers-harness/shot.cjs +++ b/scripts/workers-harness/shot.cjs @@ -1606,7 +1606,7 @@ async function handyP4(browser, base) { const reach2 = await reachOf(page, '.wk-pult-reply textarea, .wk-pult-reply .wk-pult-panel-foot .btn') const area = panel.locator('textarea') const areaBox = await area.evaluate((el) => { const r = el.getBoundingClientRect(); return { left: Math.round(r.left), right: Math.round(r.right), height: Math.round(r.height) } }) - check('handy-p4: Antwortfeld: Textfeld und „Jetzt senden“ im Fenster, nicht verdeckt, Knopf mindestens 40 px hoch, Feld mindestens 100 px hoch', reach2.length === 2 && badReach(reach2).length === 0 && areaBox.left >= 0 && areaBox.right <= 390 && areaBox.height >= 100, { reach2, areaBox }) + check('handy-p4: Antwortfeld: Textfeld, „Abbrechen“ und „Jetzt senden“ im Fenster, nicht verdeckt, Knöpfe mindestens 40 px hoch, Feld mindestens 100 px hoch', reach2.length === 3 && badReach(reach2).length === 0 && areaBox.left >= 0 && areaBox.right <= 390 && areaBox.height >= 100, { reach2, areaBox }) await panel.scrollIntoViewIfNeeded() await shoot(page, 'handy-p4-antwort-offen.png') await area.fill('x'.repeat(400) + ' https://www.sv-namborn.example/' + 'lang/'.repeat(30)) @@ -1676,7 +1676,7 @@ async function handyP4(browser, base) { await setPultFault(page, 'paste', null) await noScroll('beide Einfüge-Felder offen, 413 sichtbar') const reach6 = await reachOf(page, '.wk-pult-paste textarea, .wk-pult-paste .wk-pult-panel-foot .btn, li.wk-pult-row .wk-pult-actions > button') - check('handy-p4: Einfüge-Felder, „Einfügen“ und „Antwort des Kunden einfügen“ sind erreichbar (im Fenster, nicht verdeckt, Knöpfe mindestens 40 px hoch)', reach6.length === 6 && badReach(reach6).length === 0, { count: reach6.length, bad: badReach(reach6) }) + check('handy-p4: Einfüge-Felder, „Abbrechen“, „Einfügen“ und „Antwort des Kunden einfügen“ sind erreichbar (im Fenster, nicht verdeckt, Knöpfe mindestens 40 px hoch)', reach6.length === 8 && badReach(reach6).length === 0, { count: reach6.length, bad: badReach(reach6) }) await plat.scrollIntoViewIfNeeded() await shoot(page, 'handy-p4-einfuegen-413.png') await shoot(page, 'handy-p4-einfuegen-ganz.png', { fullPage: true }) diff --git a/src/components/workers/PultList.jsx b/src/components/workers/PultList.jsx index 3d0ce6b..cd191fc 100644 --- a/src/components/workers/PultList.jsx +++ b/src/components/workers/PultList.jsx @@ -47,16 +47,28 @@ function rowName(label, title, joiner = ': ') { } // Aufgeklapptes Feld unter den Aktionen: „Als Mensch antworten“ (.wk-pult-reply) und „Antwort des Kunden einfügen“ (.wk-pult-paste). -// Textfeld, Zähler (Zeichen wie der Dienst sie zählt, höchstens REPLY_TEXT_MAX) und ein Knopf; die Prüfung macht die Zeile beim Absenden. -function TextPanel({ className, label, hint, value, onChange, submitLabel, onSubmit, busy }) { +// Textfeld, Zähler (Zeichen wie der Dienst sie zählt, höchstens REPLY_TEXT_MAX) und zwei Knöpfe; die Prüfung macht die Zeile beim Absenden. +// Esc (aus dem ganzen Feld heraus, nicht nur aus dem Textfeld) und „Abbrechen“ schließen das Feld, der eingegebene Text bleibt in der Liste erhalten. +// Während einer Anfrage ist beides gesperrt: das Feld soll nicht mitten im Senden verschwinden. +function TextPanel({ className, label, hint, value, onChange, submitLabel, onSubmit, onClose, busy }) { const count = charCount(value) + // preventDefault: die Handy-Leiste (App.jsx) schließt bei Esc nur, wenn das Ereignis nicht behandelt wurde + const onKeyDown = (e) => { + if (e.key !== 'Escape' || busy) return + e.preventDefault() + e.stopPropagation() + onClose() + } return ( -
+
{hint &&

{hint}

}