fix(boards): add missing drag delay for touch and extract shared signal

Add cdkDragStartDelay to board-panel drag items, which was missing
entirely. Extract the repeated `isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0`
expression into a shared `dragDelayForTouch` computed signal and refactor
all 8 components to use it.
This commit is contained in:
Johannes Millan 2026-03-30 17:43:11 +02:00
parent 946339a035
commit 34b086b4c7
17 changed files with 31 additions and 35 deletions

View file

@ -41,6 +41,7 @@
<planner-task
cdkDrag
[cdkDragData]="task"
[cdkDragStartDelay]="dragDelayForTouch()"
[task]="task"
[tagsToHide]="panelCfg().includedTagIds || []"
>

View file

@ -37,6 +37,7 @@ import { DialogScheduleTaskComponent } from '../../planner/dialog-schedule-task/
import { MatDialog } from '@angular/material/dialog';
import { fastArrayCompare } from '../../../util/fast-array-compare';
import { first, take } from 'rxjs/operators';
import { dragDelayForTouch } from '../../../util/input-intent';
import { ShortPlannedAtPipe } from '../../../ui/pipes/short-planned-at.pipe';
import { MsToStringPipe } from '../../../ui/duration/ms-to-string.pipe';
import { selectUnarchivedProjects } from '../../project/store/project.selectors';
@ -66,6 +67,7 @@ import {
})
export class BoardPanelComponent {
T = T;
dragDelayForTouch = dragDelayForTouch;
panelCfg = input.required<BoardPanelCfg>();
editBoard = output<void>();

View file

@ -33,7 +33,7 @@
@for (note of notes; track note.id) {
<div
cdkDrag
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
>
<note
[isFocus]="isElementWasAdded && $index === 0"

View file

@ -21,8 +21,8 @@ import { MatIcon } from '@angular/material/icon';
import { NoteComponent } from '../note/note.component';
import { AsyncPipe } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { DRAG_DELAY_FOR_TOUCH, HISTORY_STATE } from '../../../app.constants';
import { isTouchActive } from '../../../util/input-intent';
import { HISTORY_STATE } from '../../../app.constants';
import { dragDelayForTouch } from '../../../util/input-intent';
import { LayoutService } from 'src/app/core-ui/layout/layout.service';
import { IS_MOBILE } from 'src/app/util/is-mobile';
@ -116,6 +116,5 @@ export class NotesComponent implements OnInit {
});
}
protected readonly DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly isTouchActive = isTouchActive;
protected readonly dragDelayForTouch = dragDelayForTouch;
}

View file

@ -22,7 +22,7 @@
<planner-task
cdkDrag
[cdkDragData]="task"
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
[cdkDragLockAxis]="isXs() ? 'y' : ''"
[task]="task"
[day]=""

View file

@ -15,8 +15,7 @@ import { MatIcon } from '@angular/material/icon';
import { TaskCopy } from '../../tasks/task.model';
import { OVERDUE_LIST_ID } from '../planner.model';
import { TranslatePipe } from '@ngx-translate/core';
import { isTouchActive } from '../../../util/input-intent';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { dragDelayForTouch } from '../../../util/input-intent';
import { LayoutService } from '../../../core-ui/layout/layout.service';
@Component({
@ -47,8 +46,7 @@ export class PlannerDayOverdueComponent {
OVERDUE_LIST_ID = OVERDUE_LIST_ID;
protected readonly T = T;
protected readonly isTouchActive = isTouchActive;
protected readonly DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly dragDelayForTouch = dragDelayForTouch;
// Lock Y-axis on small screens only — on wider screens the planner uses a
// multi-column grid where cross-column dragging requires horizontal movement.
protected readonly isXs = this._layoutService.isXs;

View file

@ -43,7 +43,7 @@
<planner-task
cdkDrag
[cdkDragData]="task"
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
[cdkDragLockAxis]="isXs() ? 'y' : ''"
[task]="task"
[day]="day.dayDate"
@ -128,7 +128,7 @@
[task]="scheduledItem.task"
[day]="day.dayDate"
[cdkDragData]="scheduledItem.task"
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
[cdkDragLockAxis]="isXs() ? 'y' : ''"
></planner-task>
}

View file

@ -32,8 +32,7 @@ import { ShortTimeHtmlPipe } from '../../../ui/pipes/short-time-html.pipe';
import { TranslatePipe } from '@ngx-translate/core';
import { ShortDate2Pipe } from '../../../ui/pipes/short-date2.pipe';
import { ProgressBarComponent } from '../../../ui/progress-bar/progress-bar.component';
import { isTouchActive } from '../../../util/input-intent';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { dragDelayForTouch } from '../../../util/input-intent';
import { LayoutService } from '../../../core-ui/layout/layout.service';
@Component({
@ -78,8 +77,7 @@ export class PlannerDayComponent {
protected readonly T = T;
protected readonly SCHEDULE_ITEM_TYPE = ScheduleItemType;
protected readonly isTouchActive = isTouchActive;
protected readonly DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly dragDelayForTouch = dragDelayForTouch;
// Lock Y-axis on small screens only — on wider screens the planner uses a
// multi-column grid where cross-column dragging requires horizontal movement.
protected readonly isXs = this._layoutService.isXs;

View file

@ -136,7 +136,7 @@
(cdkDragMoved)="dragMoved($event)"
(cdkDragStarted)="dragStarted($event)"
(cdkDragReleased)="dragReleased($event)"
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
></schedule-event>
} @else {
<schedule-event

View file

@ -23,8 +23,7 @@ import { ScheduleEventComponent } from '../schedule-event/schedule-event.compone
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { MatIcon } from '@angular/material/icon';
import { T } from '../../../t.const';
import { isTouchActive } from '../../../util/input-intent';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { dragDelayForTouch, isTouchActive } from '../../../util/input-intent';
import { MatTooltip } from '@angular/material/tooltip';
import { DateTimeFormatService } from '../../../core/date-time-format/date-time-format.service';
import { LocaleDatePipe } from 'src/app/ui/pipes/locale-date.pipe';
@ -84,7 +83,7 @@ export class ScheduleWeekComponent implements OnInit, AfterViewInit, OnDestroy {
FH = FH;
protected readonly isTouchActive = isTouchActive;
DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
dragDelayForTouch = dragDelayForTouch;
SVEType: typeof SVEType = SVEType;
T: typeof T = T;
protected readonly isDraggableSE = isDraggableSE;

View file

@ -50,7 +50,7 @@
<div
class="habit-row"
cdkDrag
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
>
<div
class="habit-title"

View file

@ -22,8 +22,7 @@ import { DialogConfirmComponent } from '../../../ui/dialog-confirm/dialog-confir
import { EMPTY_SIMPLE_COUNTER } from '../simple-counter.const';
import { MatTooltipModule } from '@angular/material/tooltip';
import { moveItemInArray } from '../../../util/move-item-in-array';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { isTouchActive } from '../../../util/input-intent';
import { dragDelayForTouch } from '../../../util/input-intent';
import { LocaleDatePipe } from 'src/app/ui/pipes/locale-date.pipe';
import { DateTimeFormatService } from 'src/app/core/date-time-format/date-time-format.service';
@ -57,8 +56,7 @@ export class HabitTrackerComponent {
T = T;
SimpleCounterType = SimpleCounterType;
DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly isTouchActive = isTouchActive;
dragDelayForTouch = dragDelayForTouch;
dayOffset = signal(0);

View file

@ -37,7 +37,7 @@
[isBacklog]="isBacklog()"
[task]="task"
cdkDrag
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
[cdkDragLockAxis]="isXs() ? 'y' : ''"
[cdkDragDisabled]="listModelId() === 'LATER_TODAY'"
[cdkDragData]="task"

View file

@ -42,8 +42,7 @@ import { TaskViewCustomizerService } from '../../task-view-customizer/task-view-
import { TaskLog } from '../../../core/log';
import { ScheduleExternalDragService } from '../../schedule/schedule-week/schedule-external-drag.service';
import { DEFAULT_OPTIONS } from '../../task-view-customizer/types';
import { isTouchActive } from '../../../util/input-intent';
import { DRAG_DELAY_FOR_TOUCH } from '../../../app.constants';
import { dragDelayForTouch } from '../../../util/input-intent';
export type TaskListId = 'PARENT' | 'SUB';
export type ListModelId = DropListModelSource | string;
@ -79,8 +78,7 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
private _scheduleExternalDragService = inject(ScheduleExternalDragService);
dropListService = inject(DropListService);
private _layoutService = inject(LayoutService);
protected readonly isTouchActive = isTouchActive;
protected readonly DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly dragDelayForTouch = dragDelayForTouch;
// Lock Y-axis on small screens only — on wider screens the task list may sit
// beside a side-nav or other drop targets that require horizontal dragging.
protected readonly isXs = this._layoutService.isXs;

View file

@ -51,7 +51,7 @@
class="item"
cdkDrag
[cdkDragData]="node.id"
[cdkDragStartDelay]="isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0"
[cdkDragStartDelay]="dragDelayForTouch()"
cdkDragLockAxis="y"
[ngClass]="{
'is-folder': folder,

View file

@ -38,8 +38,7 @@ import { TreeIndicatorService } from './tree-indicator.service';
import { TREE_CONSTANTS } from './tree-constants';
import { assertTreeId } from './tree-guards';
import { expandCollapseAni } from './tree.animations';
import { DRAG_DELAY_FOR_TOUCH } from '../../app.constants';
import { isTouchActive } from '../../util/input-intent';
import { dragDelayForTouch } from '../../util/input-intent';
@Component({
selector: 'tree-dnd',
@ -74,8 +73,7 @@ export class TreeDndComponent<TData = unknown> {
readonly isDragInvalid = signal<boolean>(false);
readonly isRootOver = signal<boolean>(false);
readonly indicatorStyle = this._indicatorService.indicatorStyle;
protected readonly DRAG_DELAY_FOR_TOUCH = DRAG_DELAY_FOR_TOUCH;
protected readonly isTouchActive = isTouchActive;
protected readonly dragDelayForTouch = dragDelayForTouch;
// === PRIVATE STATE ===
/**

View file

@ -2,6 +2,7 @@ import { computed } from '@angular/core';
import { deviceType } from 'detect-it';
import { IS_TOUCH_ONLY } from './is-touch-only';
import { _inputIntentSignal } from '../core/input-intent/input-intent.service';
import { DRAG_DELAY_FOR_TOUCH } from '../app.constants';
export const isTouchActive = computed(() => {
if (deviceType !== 'hybrid') {
@ -9,3 +10,7 @@ export const isTouchActive = computed(() => {
}
return _inputIntentSignal() === 'touch';
});
export const dragDelayForTouch = computed(() =>
isTouchActive() ? DRAG_DELAY_FOR_TOUCH : 0,
);