refactor(dragdrop): generalize createBlockDragDrop<T extends { id: string }>

Removes the hard-typed TranscriptionBlockData constraint so JourneyEditor
can reuse the pointer-drag module without importing transcription types.
Selector contract (data-block-wrapper / data-drag-handle) unchanged.
Adds type-regression guard test verified via tsc --noEmit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-09 12:30:29 +02:00
parent bee055e615
commit 4de664f4f6
2 changed files with 33 additions and 6 deletions

View File

@@ -1,7 +1,33 @@
import { describe, it, expect, vi } from 'vitest'; import { describe, it, expect, vi, expectTypeOf } from 'vitest';
import { createBlockDragDrop } from './useBlockDragDrop.svelte'; import { createBlockDragDrop } from './useBlockDragDrop.svelte';
import type { TranscriptionBlockData } from '$lib/shared/types'; import type { TranscriptionBlockData } from '$lib/shared/types';
// ---------------------------------------------------------------------------
// Type-regression guard: createBlockDragDrop must accept any T extends {id: string}
// so JourneyEditor can reuse it without importing TranscriptionBlockData.
// This test fails with "Expected 0 type arguments, but got 1" via tsc --noEmit
// until the function is made generic.
// ---------------------------------------------------------------------------
describe('createBlockDragDrop — generic type guard', () => {
it('accepts items shaped as { id: string; position: number } — not only TranscriptionBlockData', () => {
type SimpleItem = { id: string; position: number };
const items: SimpleItem[] = [
{ id: 'item-1', position: 0 },
{ id: 'item-2', position: 1 }
];
const onReorder = vi.fn();
const dd = createBlockDragDrop<SimpleItem>({ getSortedBlocks: () => items, onReorder });
// Verify the hook is functional with the new type — state reads must work
expect(dd.draggedBlockId).toBeNull();
expect(dd.dragOffsetY).toBe(0);
});
it('TranscriptionBlockData caller still compiles — regression guard for existing transcription editor', () => {
// If the generic constraint is wrong this line fails tsc --noEmit
expectTypeOf(createBlockDragDrop<TranscriptionBlockData>).toBeFunction();
});
});
function makeBlock(id: string, sortOrder: number): TranscriptionBlockData { function makeBlock(id: string, sortOrder: number): TranscriptionBlockData {
return { return {
id, id,

View File

@@ -1,11 +1,12 @@
import type { TranscriptionBlockData } from '$lib/shared/types'; type Options<T extends { id: string }> = {
getSortedBlocks: () => T[];
type Options = {
getSortedBlocks: () => TranscriptionBlockData[];
onReorder: (blockIds: string[]) => void; onReorder: (blockIds: string[]) => void;
}; };
export function createBlockDragDrop({ getSortedBlocks, onReorder }: Options) { export function createBlockDragDrop<T extends { id: string }>({
getSortedBlocks,
onReorder
}: Options<T>) {
let draggedBlockId = $state<string | null>(null); let draggedBlockId = $state<string | null>(null);
let dropTargetIdx = $state<number | null>(null); let dropTargetIdx = $state<number | null>(null);
let dragOffsetY = $state(0); let dragOffsetY = $state(0);