diff --git a/src/uix/eidos/components/words/words-block-drag-type.ts b/src/uix/eidos/components/words/words-block-drag-type.ts new file mode 100644 index 000000000..c678c368d --- /dev/null +++ b/src/uix/eidos/components/words/words-block-drag-type.ts @@ -0,0 +1,8 @@ +/** + * Private clipboard MIME the block grip writes on `dragstart` (carrying the + * dragged block's top-level index as its data). The drag-reorder controller + * reads it on `dragover` / `drop` to tell a block reorder apart from a native + * text drag — every drop handler bails unless this type is present, so + * selecting text and dragging it keeps the browser's default behaviour. + */ +export const WORDS_BLOCK_DRAG_TYPE = 'application/x-words-block'; diff --git a/src/uix/eidos/components/words/words-block-drag.svelte b/src/uix/eidos/components/words/words-block-drag.svelte new file mode 100644 index 000000000..baa91b867 --- /dev/null +++ b/src/uix/eidos/components/words/words-block-drag.svelte @@ -0,0 +1,118 @@ + + +{#if line} +
+{/if} diff --git a/src/uix/eidos/components/words/words-block-gutter.svelte b/src/uix/eidos/components/words/words-block-gutter.svelte index 43bdda88d..59d8dd2b8 100644 --- a/src/uix/eidos/components/words/words-block-gutter.svelte +++ b/src/uix/eidos/components/words/words-block-gutter.svelte @@ -29,6 +29,7 @@ } from '$soma/components/words'; import { pickImageFile } from './words-image-file'; import { WORDS_MENU_LANGS as L } from './langs-menu'; + import { WORDS_BLOCK_DRAG_TYPE } from './words-block-drag-type'; let { api, @@ -200,6 +201,15 @@ // the next selectionchange). api.selectAtomicBlock(index, [index]); } + // Start an HTML5 drag carrying this block's top-level index. The drop + // controller (`words-block-drag.svelte`) reads it on drop and repositions + // the block. The grip stays a click target too (the menu opens on click, + // the drag on a press-and-move) — they don't collide. + function onGripDragStart(event: DragEvent) { + if (index < 0 || !event.dataTransfer) return; + event.dataTransfer.setData(WORDS_BLOCK_DRAG_TYPE, String(index)); + event.dataTransfer.effectAllowed = 'move'; + } function moveUp() { if (index > 0) api.applyCommand({ type: 'moveBlock', blockIndex: index, direction: 'up' }); } @@ -326,6 +336,8 @@ rounded="md" aria-label="Block actions" data-words-block-handle + draggable={true} + ondragstart={onGripDragStart} > {#snippet icon()}