mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:41:09 +02:00
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:
parent
448cfb9010
commit
287a62a3fb
4 changed files with 42 additions and 14 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue