fix(tasks): refocus add-task input after clicking + button (#8703)

Clicking the + button moved focus onto the button, which unmounts once
the input clears, dropping focus to <body>. Route the click through a
new onSubmitBtnClick() that refocuses the input after addTask() settles
so the next task can be typed right away. The Enter-key path already
retained input focus, so it is unchanged.
This commit is contained in:
Johannes Millan 2026-07-02 12:53:30 +02:00 committed by GitHub
parent 6c1117b7b0
commit db99a4c345
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 57 additions and 1 deletions

View file

@ -32,7 +32,7 @@
<button
mat-icon-button
class="switch-add-to-btn e2e-add-task-submit"
(click)="addTask()"
(click)="onSubmitBtnClick()"
type="submit"
[matTooltip]="T.F.TASK.ADD_TASK_BAR.TOOLTIP_ADD_TASK | translate"
matTooltipPosition="above"

View file

@ -434,6 +434,47 @@ describe('AddTaskBarComponent', () => {
});
});
describe('onSubmitBtnClick', () => {
it('should add the task and refocus the input for rapid entry', async () => {
mockTaskService.add.and.returnValue('task-1');
const focusSpy = spyOn(component, 'focusInput');
component.stateService.updateInputTxt('Buy milk');
component.stateService.updateCleanText('Buy milk');
component.onSubmitBtnClick();
// Wait for the addTask promise (and its .finally) to settle.
await Promise.resolve();
expect(mockTaskService.add).toHaveBeenCalled();
expect(focusSpy).toHaveBeenCalled();
});
it('should refocus the input even when nothing is added', async () => {
const focusSpy = spyOn(component, 'focusInput');
component.stateService.updateInputTxt(' ');
component.onSubmitBtnClick();
await Promise.resolve();
expect(mockTaskService.add).not.toHaveBeenCalled();
expect(focusSpy).toHaveBeenCalled();
});
it('should NOT refocus for CUSTOM repeat (it opens a dialog)', async () => {
mockTaskService.add.and.returnValue('task-1');
const focusSpy = spyOn(component, 'focusInput');
component.stateService.updateInputTxt('Buy milk');
component.stateService.updateCleanText('Buy milk');
component.stateService.updateRepeatSetting('CUSTOM');
component.onSubmitBtnClick();
await Promise.resolve();
expect(mockTaskService.add).toHaveBeenCalled();
expect(focusSpy).not.toHaveBeenCalled();
});
});
describe('note panel', () => {
it('toggleNote should flip the expanded state', () => {
// focusInput re-focuses the title input, which tries to open the

View file

@ -571,6 +571,21 @@ export class AddTaskBarComponent implements AfterViewInit, OnInit, OnDestroy {
}
}
onSubmitBtnClick(): void {
// Clicking the + button moves focus onto the button, which then vanishes
// once the input clears — refocus the input so the next task can be typed
// right away. (The Enter-key submit path never loses input focus.)
// Skip the refocus for CUSTOM repeat: addTask() opens the repeat-config
// dialog asynchronously, and refocusing would steal focus from it.
const willOpenRepeatDialog =
this.stateService.state().repeatQuickSetting === 'CUSTOM';
void this.addTask().finally(() => {
if (!willOpenRepeatDialog) {
this.focusInput();
}
});
}
onTaskSuggestionActivated(suggestion: AddTaskSuggestion | null): void {
this.activatedSuggestion$.next(suggestion);
}