Skip to content

[ux-timeline-lanes-floating-remove-touch-target] Floating lane overlay and audio blocks have sub-16px delete touch targets #5426

Description

@atomantic

Problem

In VideoTimelineLanes (client/src/components/media/VideoTimelineLanes.jsx:133-143), LaneBlock renders items inside the free-floating Overlays and Audio tracks:

export const LaneBlock = memo(function LaneBlock({
  entry, label, tone, isSelected, isMissing, pxPerSec, onSelect, onRemove,
}) {
  const dur = Math.max(0.05, entry.durationSec || 0);
  const style = {
    left: `${(entry.startSec || 0) * pxPerSec}px`,
    width: `${Math.max(28, dur * pxPerSec)}px`,
  };
  return (
    <div
      style={style}
      className={`absolute top-1 bottom-1 rounded border cursor-pointer overflow-hidden ...`}
      onClick={() => onSelect(entry._key)}
      {...clickableProps(() => onSelect(entry._key))}
    >
      <span className="absolute inset-x-1 top-0.5 text-[9px] text-white truncate pointer-events-none">
        {isMissing ? '(missing)' : label}
      </span>
      <button
        type="button"
        onClick={(e) => { e.stopPropagation(); onRemove(entry._key); }}
        onPointerDown={(e) => e.stopPropagation()}
        className="absolute bottom-0 right-0 p-0.5 text-white/70 hover:text-port-error"
        title="Remove"
        aria-label={`Remove ${label} from timeline`}
      >
        <X className="w-3 h-3" aria-hidden="true" />
      </button>
    </div>
  );
});

While TimelineBlock (in the video lane) explicitly implements a 44px touch target (className="... min-w-[44px] min-h-[44px] ..." covered by unit tests in VideoTimelineLanes.test.jsx:49-59), LaneBlock's remove button uses p-0.5 with a 12px X icon, resulting in a ~16px × 16px hit target.

Trigger

  1. On a mobile or touch device, open /media/timeline/:projectId.
  2. Add an overlay or audio track to the timeline.
  3. Attempt to tap the remove X icon on the overlay or audio track block in the timeline.

Impact

  • Because the remove button is only ~16px × 16px and is nested inside a clickable container (onClick={() => onSelect(entry._key)}), finger taps almost always trigger the parent selection handler rather than the remove handler.
  • Removing an overlay or audio bed directly from the timeline on touch screens is extremely frustrating and error-prone.

Proposed Fix

  1. Increase the touch hit bounds of the remove button in LaneBlock (inline-flex items-center justify-center min-w-[28px] min-h-[28px] p-1 sm:min-w-0 sm:min-h-0 sm:p-0.5).
  2. Alternatively, ensure the block is easily removable via the Inspector's RemoveButton when selected, and provide a clear tap target.
  3. Files touched:
    • client/src/components/media/VideoTimelineLanes.jsx
    • client/src/components/media/VideoTimelineLanes.test.jsx

Acceptance Criteria

  • LaneBlock remove button has a touch hit target of at least 28–44px (or adequate hit area padding) on touch devices.
  • Tapping remove deletes the overlay/audio entry without triggering selection.
  • Unit tests in VideoTimelineLanes.test.jsx verify the remove button dimensions and isolated click behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:uiUI components and stylingeffort:lowEffort: lowmodel:lightModel size: lightplanTracked by /do:replanuxUser experience

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions