fix(splitscreen): fix resize handle not working after first drag

- Add transparent overlay during resize to capture all mouse events
- Disable iframe pointer-events while dragging to prevent event stealing
- Make PanelControls always visible for better UX
- Fix TypeScript type for dividerPosition state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-12-12 13:12:41 +01:00
parent 448cfb9010
commit 287a62a3fb
4 changed files with 42 additions and 14 deletions

View file

@ -69,12 +69,7 @@
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
z-index: 20;
opacity: 0;
transition: opacity 0.2s ease;
}
.app-panel:hover .panel-controls,
.panel-controls:focus-within {
/* Always visible - important for closing the panel */
opacity: 1;
}

View file

@ -10,16 +10,22 @@
position: number;
onResize: (position: number) => void;
onReset: () => void;
onDragStateChange?: (isDragging: boolean) => void;
}
let { position, onResize, onReset }: Props = $props();
let { position, onResize, onReset, onDragStateChange }: Props = $props();
let isDragging = $state(false);
function setDragging(value: boolean) {
isDragging = value;
onDragStateChange?.(value);
}
let containerRef: HTMLElement | null = null;
function handleMouseDown(event: MouseEvent) {
event.preventDefault();
isDragging = true;
setDragging(true);
const handleMouseMove = (e: MouseEvent) => {
if (!containerRef) return;
@ -39,7 +45,7 @@
};
const handleMouseUp = () => {
isDragging = false;
setDragging(false);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
@ -50,7 +56,7 @@
function handleTouchStart(event: TouchEvent) {
event.preventDefault();
isDragging = true;
setDragging(true);
const handleTouchMove = (e: TouchEvent) => {
if (!containerRef || !e.touches[0]) return;
@ -70,7 +76,7 @@
};
const handleTouchEnd = () => {
isDragging = false;
setDragging(false);
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleTouchEnd);
};

View file

@ -5,7 +5,6 @@
*/
import type { Snippet } from 'svelte';
import { onMount } from 'svelte';
import { getSplitPanelContext } from '../stores/split-panel.svelte.js';
import AppPanel from './AppPanel.svelte';
import PanelControls from './PanelControls.svelte';
@ -20,6 +19,9 @@
const splitPanel = getSplitPanelContext();
// Track if resize handle is being dragged - used to disable iframe pointer events
let isResizing = $state(false);
// Grid template based on divider position
let gridTemplate = $derived(
splitPanel.isActive && splitPanel.rightPanel ? `${splitPanel.dividerPosition}% 6px 1fr` : '1fr'
@ -32,13 +34,23 @@
function handleReset() {
splitPanel.resetDividerPosition();
}
function handleDragStateChange(isDragging: boolean) {
isResizing = isDragging;
}
</script>
<div
class="split-pane-container {className}"
class:split-active={splitPanel.isActive && splitPanel.rightPanel}
class:resizing={isResizing}
style:--grid-template={gridTemplate}
>
<!-- Overlay during resize to capture all mouse events -->
{#if isResizing}
<div class="resize-overlay"></div>
{/if}
<div class="main-panel">
{@render children()}
</div>
@ -48,9 +60,10 @@
position={splitPanel.dividerPosition}
onResize={handleResize}
onReset={handleReset}
onDragStateChange={handleDragStateChange}
/>
<div class="side-panel">
<div class="side-panel" class:resizing={isResizing}>
<AppPanel panel={splitPanel.rightPanel} />
<PanelControls
panelName={splitPanel.rightPanel.name || splitPanel.rightPanel.appId}
@ -69,6 +82,15 @@
height: 100%;
min-height: 0;
overflow: hidden;
position: relative;
}
/* Transparent overlay during resize - captures all mouse events */
.resize-overlay {
position: absolute;
inset: 0;
z-index: 100;
cursor: col-resize;
}
.main-panel {
@ -89,6 +111,11 @@
overflow: hidden;
}
/* Disable iframe pointer events during resize to prevent event stealing */
.side-panel.resizing :global(iframe) {
pointer-events: none;
}
/* Ensure proper stacking */
.split-active .main-panel {
z-index: 1;

View file

@ -74,7 +74,7 @@ export function createSplitPanelStore(
// Reactive state using Svelte 5 runes
let isActive = $state(false);
let rightPanel = $state<PanelConfig | null>(null);
let dividerPosition = $state(DIVIDER_CONSTRAINTS.DEFAULT);
let dividerPosition = $state<number>(DIVIDER_CONSTRAINTS.DEFAULT);
let isMobile = $state(false);
// Storage config for persistence