Skip to content

Commit

Permalink
123
Browse files Browse the repository at this point in the history
  • Loading branch information
pivanov committed Dec 13, 2024
1 parent d6548f0 commit 55d6733
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 226 deletions.
23 changes: 0 additions & 23 deletions packages/scan/src/core/web/components/widget/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,3 @@ export const LOCALSTORAGE_KEY = 'react-scan-widget';
export const SAFE_AREA = 20;
export const MIN_SIZE = { width: 360, height: 240 };
export const MINIMIZED_SIZE = { width: 'min-content' } as const;
export const RESIZE_HANDLE_SIZE = 16; // 4rem from the Tailwind class

export const CORNER_CONFIGS = {
'top-left': {
position: { x: SAFE_AREA, y: SAFE_AREA },
resize: { position: 'bottom-0 right-0 translate-x-1/2 translate-y-1/2', direction: 'bottom-right' }
},
'top-right': {
position: { x: (width: number) => window.innerWidth - width - SAFE_AREA, y: SAFE_AREA },
resize: { position: 'bottom-0 left-0 -translate-x-1/2 translate-y-1/2', direction: 'bottom-left' }
},
'bottom-left': {
position: { x: SAFE_AREA, y: (height: number) => window.innerHeight - height - SAFE_AREA },
resize: { position: 'top-0 right-0 translate-x-1/2 -translate-y-1/2', direction: 'top-right' }
},
'bottom-right': {
position: {
x: (width: number) => window.innerWidth - width - SAFE_AREA,
y: (height: number) => window.innerHeight - height - SAFE_AREA
},
resize: { position: 'top-0 left-0 -translate-x-1/2 -translate-y-1/2', direction: 'top-left' }
}
} as const;
193 changes: 58 additions & 135 deletions packages/scan/src/core/web/components/widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { getCompositeComponentFromElement } from '@web-inspect-element/utils';
import { Store } from 'src/core';
import { signalWidget, signalRefContainer, updateDimensions } from '../../state';
import { Header } from './header';
import { type WidgetSettings, type Corner, type Position } from './types'
import { MIN_SIZE, SAFE_AREA, RESIZE_HANDLE_SIZE, LOCALSTORAGE_KEY } from './constants';
import { type WidgetSettings, type Corner } from './types'
import { MIN_SIZE, SAFE_AREA, LOCALSTORAGE_KEY } from './constants';
import Toolbar from './toolbar';
import { ResizeHandle } from './resize-handle';
import { calculatePosition, calculateDimensions } from './helpers';
Expand All @@ -19,10 +19,6 @@ export const Widget = () => {
const refContainer = useRef<HTMLDivElement | null>(null);
const refPropContainer = useRef<HTMLDivElement>(null);
const refFooter = useRef<HTMLDivElement>(null);
const refInitialFooterHeight = useRef<number>(0);

const refDragStart = useRef<Position | null>(null);
const refInitialPosition = useRef<Position | null>(null);

const refInitialMinimizedWidth = useRef<number>(0);
const refInitialMinimizedHeight = useRef<number>(0);
Expand Down Expand Up @@ -78,153 +74,82 @@ export const Widget = () => {
return true;
}, [isInspectFocused]);

const updateState = useCallback((updates: Partial<WidgetSettings>) => {
signalWidget.value = { ...signalWidget.value, ...updates };

if (!refContainer.current) return;

requestAnimationFrame(() => {
if (!refContainer.current) return;

const { corner } = signalWidget.value;
const width = updates.size?.width ?? signalWidget.value.size.width;
const height = isInspectFocused
? (updates.size?.height ?? signalWidget.value.size.height)
: refInitialFooterHeight.current;

const position = calculatePosition(corner, width, height);

Object.assign(refContainer.current.style, {
width: `${width}px`,
height: `${height}px`,
transform: `translate(${position.x}px, ${position.y}px)`
});

signalWidget.value = {
...signalWidget.value,
position
};

if (isInspectFocused) {
saveLocalStorage(LOCALSTORAGE_KEY, {
corner,
size: {
width: signalWidget.value.lastExpandedWidth,
height: signalWidget.value.lastExpandedHeight
}
});
}
});
}, []);

const handleMouseDown = useCallback((event: JSX.TargetedMouseEvent<HTMLDivElement>) => {
if ((event.target as HTMLElement).closest('button')) return;
if (!refContainer.current) return;

refContainer.current.style.transition = 'none';

const rect = refContainer.current.getBoundingClientRect();
const isClickInResizeArea = (() => {
const clickX = event.clientX - rect.left;
const clickY = event.clientY - rect.top;

switch (signalWidget.value.corner) {
case 'top-left':
return (
clickX >= rect.width - RESIZE_HANDLE_SIZE &&
clickY >= rect.height - RESIZE_HANDLE_SIZE
);
case 'top-right':
return (
clickX <= RESIZE_HANDLE_SIZE &&
clickY >= rect.height - RESIZE_HANDLE_SIZE
);
case 'bottom-left':
return (
clickX >= rect.width - RESIZE_HANDLE_SIZE &&
clickY <= RESIZE_HANDLE_SIZE
);
case 'bottom-right':
return (
clickX <= RESIZE_HANDLE_SIZE &&
clickY <= RESIZE_HANDLE_SIZE
);
}
})();
event.preventDefault();

if (isClickInResizeArea) {
return
}
const container = refContainer.current;
const { size } = signalWidget.value;
const startX = event.clientX;
const startY = event.clientY;
const initialX = signalWidget.value.position.x;
const initialY = signalWidget.value.position.y;

event.preventDefault();
container.style.transition = 'none';

refDragStart.current = { x: event.clientX, y: event.clientY };
refInitialPosition.current = signalWidget.value.position;
let currentX = initialX;
let currentY = initialY;
let rafId: number | null = null;

const handleMouseMove = (e: globalThis.MouseEvent) => {
if (!refDragStart.current || !refInitialPosition.current || !refContainer.current) return;

const deltaX = e.clientX - refDragStart.current.x;
const deltaY = e.clientY - refDragStart.current.y;

const newX = Math.min(
Math.max(SAFE_AREA, refInitialPosition.current.x + deltaX),
window.innerWidth - signalWidget.value.size.width - SAFE_AREA
);
const newY = Math.min(
Math.max(SAFE_AREA, refInitialPosition.current.y + deltaY),
window.innerHeight - signalWidget.value.size.height - SAFE_AREA
);

refContainer.current.style.transform = `translate(${newX}px, ${newY}px)`;
signalWidget.value = {
...signalWidget.value,
position: { x: newX, y: newY }
};
};
if (rafId) return;

const handleMouseUp = (e: globalThis.MouseEvent) => {
if (!refDragStart.current || !refContainer.current) return;
rafId = requestAnimationFrame(() => {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;

refContainer.current.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
currentX = initialX + deltaX;
currentY = initialY + deltaY;

const newCorner = `${e.clientY < window.innerHeight / 2
? 'top'
: 'bottom'}-${e.clientX < window.innerWidth / 2
? 'left'
: 'right'}` as Corner;
container.style.transform = `translate(${currentX}px, ${currentY}px)`;
rafId = null;
});
};

const currentSize = signalWidget.value.size;
const newPosition = calculatePosition(newCorner, currentSize.width, currentSize.height);
const handleMouseUp = () => {
if (!container) return;
if (rafId) cancelAnimationFrame(rafId);

signalWidget.value = {
...signalWidget.value,
corner: newCorner,
position: newPosition,
size: currentSize
};
requestAnimationFrame(() => {
container.style.transition = 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)';

updateDimensions();
const newCorner = `${currentY < window.innerHeight / 2 ? 'top' : 'bottom'}-${currentX < window.innerWidth / 2 ? 'left' : 'right'
}` as Corner;

refContainer.current.style.transform = `translate(${newPosition.x}px, ${newPosition.y}px)`;
const snappedPosition = calculatePosition(newCorner, size.width, size.height);
const newDimensions = calculateDimensions(size, newCorner);

container.style.transform = `translate(${snappedPosition.x}px, ${snappedPosition.y}px)`;

saveLocalStorage(LOCALSTORAGE_KEY, {
corner: newCorner,
size: {
width: signalWidget.value.lastExpandedWidth,
height: signalWidget.value.lastExpandedHeight
}
signalWidget.value = {
...signalWidget.value,
corner: newCorner,
position: snappedPosition,
dimensions: newDimensions
};

queueMicrotask(() => {
saveLocalStorage(LOCALSTORAGE_KEY, {
corner: newCorner,
size: {
width: signalWidget.value.lastExpandedWidth,
height: signalWidget.value.lastExpandedHeight
}
});
});

updateDimensions();
});

refDragStart.current = null;
refInitialPosition.current = null;
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};

document.addEventListener('mousemove', handleMouseMove, { passive: true });
document.addEventListener('mouseup', handleMouseUp, { passive: true });
}, [updateState]);
document.addEventListener('mouseup', handleMouseUp);
}, []);

useEffect(() => {
if (!refContainer.current || !shouldExpand) {
Expand Down Expand Up @@ -260,12 +185,10 @@ export const Widget = () => {

const newPosition = calculatePosition(corner, newWidth, newHeight);

Object.assign(refContainer.current.style, {
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
width: `${newWidth}px`,
height: `${newHeight}px`,
transform: `translate(${newPosition.x}px, ${newPosition.y}px)`
});
refContainer.current.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
refContainer.current.style.width = `${newWidth}px`;
refContainer.current.style.height = `${newHeight}px`;
refContainer.current.style.transform = `translate(${newPosition.x}px, ${newPosition.y}px)`;

const newDimensions = isInspectFocused ? calculateDimensions({ width: newWidth, height: newHeight }, corner) : undefined;
const newState = {
Expand Down
Loading

0 comments on commit 55d6733

Please sign in to comment.