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
- On a mobile or touch device, open
/media/timeline/:projectId.
- Add an overlay or audio track to the timeline.
- 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
- 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).
- Alternatively, ensure the block is easily removable via the Inspector's
RemoveButton when selected, and provide a clear tap target.
- Files touched:
client/src/components/media/VideoTimelineLanes.jsx
client/src/components/media/VideoTimelineLanes.test.jsx
Acceptance Criteria
Problem
In
VideoTimelineLanes(client/src/components/media/VideoTimelineLanes.jsx:133-143),LaneBlockrenders items inside the free-floating Overlays and Audio tracks:While
TimelineBlock(in the video lane) explicitly implements a 44px touch target (className="... min-w-[44px] min-h-[44px] ..."covered by unit tests inVideoTimelineLanes.test.jsx:49-59),LaneBlock's remove button usesp-0.5with a 12pxXicon, resulting in a ~16px × 16px hit target.Trigger
/media/timeline/:projectId.Xicon on the overlay or audio track block in the timeline.Impact
onClick={() => onSelect(entry._key)}), finger taps almost always trigger the parent selection handler rather than the remove handler.Proposed Fix
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).RemoveButtonwhen selected, and provide a clear tap target.client/src/components/media/VideoTimelineLanes.jsxclient/src/components/media/VideoTimelineLanes.test.jsxAcceptance Criteria
LaneBlockremove button has a touch hit target of at least 28–44px (or adequate hit area padding) on touch devices.VideoTimelineLanes.test.jsxverify the remove button dimensions and isolated click behavior.