Files
kandev/apps
João Salavisa f23d11dc64 feat(web): add voice mode to task create dialog (#1230)
* feat(web): add voice mode to task create dialog prompt

Wires the existing VoiceInputButton (introduced in #1159 for the chat
composer) into the task-create dialog's prompt toolbar so users can
dictate the initial task description.

- TaskFormInputs gains an internal insertAtCursor that splices the
  transcript at the textarea caret with a single leading space when
  it follows a non-whitespace character, matching the chat composer's
  behaviour. A pending-cursor ref + useLayoutEffect restores the
  caret position after React commits the new value.
- An optional onVoiceAutoSend prop is threaded from TaskCreateDialog
  down through DialogPromptSection -> TaskFormInputs -> VoiceInputButton.
  The dialog points it at formRef.current?.requestSubmit() so dictation
  can create the task hands-free; every existing submit gate still
  applies via the disabled submit button.
- Voice mode is gated globally on userSettings.voiceMode.enabled, so
  the button self-hides for users who turned it off in settings and
  self-greys on browsers without a usable engine.

* fix(web): invoke submit handler directly for voice auto-send

`HTMLFormElement.requestSubmit()` is missing on Safari < 16, so the
previous wiring silently failed with a TypeError on browsers where voice
mode itself works (Safari 14.5-15 supports Web Speech / Whisper Web).

Drop the form ref and call `setup.guardedHandleSubmit` with a synthetic
event instead. `guardedHandleSubmit` only reads `preventDefault` off the
event, and every validation gate (`validateForCreate`, session-mode
description/agent checks, edit-mode title check, `submitBlockedReason`)
lives inside the submit handler — so dictation with incomplete fields
still no-ops, identical to the prior requestSubmit-based behaviour.

This also matches the chat composer's pattern of calling the same submit
function the send button uses.

independent-review: voice auto-send Safari < 16 compat

* test(web): expand voice splice cases for task-create dialog

Adds adversarial coverage for the at-cursor splice helper that backs
voice-mode dictation in the task-create dialog:
- multi-line description with caret on a line boundary
- transcript with internal newlines preserved as-is
- existing tabs / newlines before the caret treated as whitespace
- session-mode renders the voice button

Splits the test file into a rendering-and-wiring `describe` and a
splice-behaviour `describe` so each arrow function stays under the
100-line `max-lines-per-function` lint cap.

qa: adversarial voice splice cases + session-mode parity

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-06-01 18:38:51 +01:00
..