diff --git a/src/uix/eidos/components/words/words-block-handle.svelte b/src/uix/eidos/components/words/words-block-handle.svelte index 729a6af21..37b205fb3 100644 --- a/src/uix/eidos/components/words/words-block-handle.svelte +++ b/src/uix/eidos/components/words/words-block-handle.svelte @@ -58,6 +58,16 @@ * (rail-px + rail-gap), so the rail's center in viewport coords * is `block.rect.left - content-px - rail-gap - rail-px/2`. */ + function cssToPx(raw: string, rootFontSize: number): number { + const trimmed = raw.trim(); + const num = parseFloat(trimmed); + if (!isFinite(num)) return 0; + if (trimmed.endsWith('rem')) return num * rootFontSize; + if (trimmed.endsWith('em')) return num * rootFontSize; + // 'px', unitless, calc()-resolved → already in px (or treat as px) + return num; + } + function rememberRailMetrics(el: HTMLElement): { railPx: number; railGap: number; @@ -65,9 +75,10 @@ } { const host = el.closest('[data-words]') ?? document.documentElement; const cs = getComputedStyle(host); - const railPx = parseFloat(cs.getPropertyValue('--_words-rail-px')) || 32; - const railGap = parseFloat(cs.getPropertyValue('--_words-rail-gap')) || 8; - const contentPx = parseFloat(cs.getPropertyValue('--_words-content-px')) || 16; + const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16; + const railPx = cssToPx(cs.getPropertyValue('--_words-rail-px'), rootFontSize) || 32; + const railGap = cssToPx(cs.getPropertyValue('--_words-rail-gap'), rootFontSize) || 8; + const contentPx = cssToPx(cs.getPropertyValue('--_words-content-px'), rootFontSize) || 16; return { railPx, railGap, contentPx }; } @@ -261,6 +272,17 @@ // the drag (dataTransfer values aren't readable in dragover). e.dataTransfer?.setData('text/plain', String(idx)); if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move'; + // Use the BLOCK ELEMENT (not the tiny grip) as the drag image so + // the user sees the whole paragraph/heading/image moving with the + // cursor. Offset puts the cursor near the grip's original spot + // (top-left of the block) so the gesture feels natural. + if (e.dataTransfer && hoverBlockEl) { + try { + e.dataTransfer.setDragImage(hoverBlockEl, 12, 12); + } catch { + /* Some browsers throw for cross-origin/iframe edge cases. */ + } + } } function ondragend() {