fix(web/m7-364): keyboard reorder + measured row height + offsetToDelta helper

This commit is contained in:
2026-05-03 21:45:32 -04:00
parent 57a353a138
commit e164d69492
4 changed files with 86 additions and 10 deletions
+24 -10
View File
@@ -1,9 +1,9 @@
<script lang="ts">
import { GripVertical, X } from 'lucide-svelte';
import { draggable } from '@neodrag/svelte';
import type { DragEventData } from '@neodrag/svelte';
import { draggable, type DragEventData } from '@neodrag/svelte';
import type { TrackRef } from '$lib/api/types';
import { playFromQueueIndex, removeFromQueue, moveQueueItem } from '$lib/player/store.svelte';
import { offsetToDelta } from './queue-row-math';
let { track, index, isCurrent } = $props<{
track: TrackRef;
@@ -11,35 +11,49 @@
isCurrent: boolean;
}>();
// Approximate row height in px — used to translate the drop offset
// into a destination index. The row's Tailwind sets h-16 (64px).
const ROW_HEIGHT = 64;
let measuredRowHeight = 64; // sensible default; replaced on dragStart
function handleDragStart(data: DragEventData) {
// The action's `data.rootNode` is the element use:draggable was applied to.
const rect = data.rootNode.getBoundingClientRect();
if (rect.height > 0) measuredRowHeight = rect.height;
}
function handleBodyClick() {
if (isCurrent) return;
playFromQueueIndex(index);
}
function handleRemove(e: MouseEvent) {
e.stopPropagation();
function handleRemove() {
removeFromQueue(index);
}
function handleDragEnd(data: DragEventData) {
const delta = Math.round(data.offsetY / ROW_HEIGHT);
const delta = offsetToDelta(data.offsetY, measuredRowHeight);
if (delta === 0) return;
moveQueueItem(index, index + delta);
}
function handleHandleKeydown(e: KeyboardEvent) {
if (e.key === 'ArrowUp') {
e.preventDefault();
moveQueueItem(index, index - 1);
} else if (e.key === 'ArrowDown') {
e.preventDefault();
moveQueueItem(index, index + 1);
}
}
</script>
<div
use:draggable={{ axis: 'y', bounds: 'parent', onDragEnd: handleDragEnd }}
use:draggable={{ axis: 'y', bounds: 'parent', onDragStart: handleDragStart, onDragEnd: handleDragEnd }}
class="flex items-center gap-2 border-b border-border px-3 py-2 h-16
{isCurrent ? 'border-l-2 border-l-accent bg-surface-hover' : ''}"
>
<button
type="button"
aria-label="Reorder track"
aria-label="Reorder track (use arrow keys)"
onkeydown={handleHandleKeydown}
class="cursor-grab text-text-secondary hover:text-text-primary flex-shrink-0"
>
<GripVertical size={16} />