mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-12 02:35:42 +00:00
fix(Map): Add new windows system and removed old
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import 'react-grid-layout/css/styles.css';
|
import 'react-grid-layout/css/styles.css';
|
||||||
import 'react-resizable/css/styles.css';
|
import 'react-resizable/css/styles.css';
|
||||||
import { WidgetGridItem, WidgetsGrid } from '@/hooks/Mapper/components/mapInterface/components';
|
|
||||||
import {
|
import {
|
||||||
LocalCharacters,
|
LocalCharacters,
|
||||||
RoutesWidget,
|
RoutesWidget,
|
||||||
@@ -9,60 +8,10 @@ import {
|
|||||||
} from '@/hooks/Mapper/components/mapInterface/widgets';
|
} from '@/hooks/Mapper/components/mapInterface/widgets';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { SESSION_KEY } from '@/hooks/Mapper/constants.ts';
|
import { SESSION_KEY } from '@/hooks/Mapper/constants.ts';
|
||||||
import { WindowManager, WindowProps } from '@/hooks/Mapper/components/ui-kit/WindowManager';
|
import { WindowManager } from '@/hooks/Mapper/components/ui-kit/WindowManager';
|
||||||
// import { debounce } from 'lodash/debounce';
|
import { WindowProps } from '@/hooks/Mapper/components/ui-kit/WindowManager/types.ts';
|
||||||
|
|
||||||
const DEFAULT_WINDOWS = [
|
const CURRENT_WINDOWS_VERSION = 2;
|
||||||
{
|
|
||||||
name: 'info',
|
|
||||||
rightOffset: 5,
|
|
||||||
width: 5,
|
|
||||||
height: 4,
|
|
||||||
item: () => <SystemInfo />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'local',
|
|
||||||
rightOffset: 5,
|
|
||||||
topOffset: 4,
|
|
||||||
width: 5,
|
|
||||||
height: 4,
|
|
||||||
item: () => <LocalCharacters />,
|
|
||||||
},
|
|
||||||
{ name: 'signatures', width: 8, height: 4, topOffset: 8, rightOffset: 12, item: () => <SystemSignatures /> },
|
|
||||||
{
|
|
||||||
name: 'routes',
|
|
||||||
rightOffset: 0,
|
|
||||||
topOffset: 8,
|
|
||||||
width: 5,
|
|
||||||
height: 6,
|
|
||||||
item: () => <RoutesWidget />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const saveWindowsToLS = (toSaveItems: WidgetGridItem[]) => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const out = toSaveItems.map(({ item, ...rest }) => rest);
|
|
||||||
localStorage.setItem(SESSION_KEY.windows, JSON.stringify(out));
|
|
||||||
};
|
|
||||||
|
|
||||||
const restoreWindowsFromLS = (): WidgetGridItem[] => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const raw = localStorage.getItem(SESSION_KEY.windows);
|
|
||||||
if (!raw) {
|
|
||||||
console.warn('No windows found in local storage!!');
|
|
||||||
return DEFAULT_WINDOWS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-debugger
|
|
||||||
const out = (JSON.parse(raw) as Omit<WidgetGridItem, 'item'>[])
|
|
||||||
.filter(x => DEFAULT_WINDOWS.find(def => def.name === x.name))
|
|
||||||
.map(x => {
|
|
||||||
const windowItem = DEFAULT_WINDOWS.find(def => def.name === x.name)?.item;
|
|
||||||
return { ...x, item: windowItem! };
|
|
||||||
});
|
|
||||||
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
const DEFAULT: WindowProps[] = [
|
const DEFAULT: WindowProps[] = [
|
||||||
{
|
{
|
||||||
@@ -95,18 +44,52 @@ const DEFAULT: WindowProps[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const MapInterface = () => {
|
type WindowsLS = {
|
||||||
return <WindowManager windows={DEFAULT} dragSelector=".react-grid-dragHandleExample" />;
|
windows: WindowProps[];
|
||||||
|
version: number;
|
||||||
// const [items, setItems] = useState<WidgetGridItem[]>(restoreWindowsFromLS);
|
};
|
||||||
//
|
|
||||||
// return (
|
const saveWindowsToLS = (toSaveItems: WindowProps[]) => {
|
||||||
// <WidgetsGrid
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
// items={items}
|
const out = toSaveItems.map(({ content, ...rest }) => rest);
|
||||||
// onChange={x => {
|
localStorage.setItem(SESSION_KEY.windows, JSON.stringify({ version: CURRENT_WINDOWS_VERSION, windows: out }));
|
||||||
// saveWindowsToLS(x);
|
};
|
||||||
// setItems(x);
|
|
||||||
// }}
|
const restoreWindowsFromLS = (): WindowProps[] => {
|
||||||
// />
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
// );
|
const raw = localStorage.getItem(SESSION_KEY.windows);
|
||||||
|
if (!raw) {
|
||||||
|
console.warn('No windows found in local storage!!');
|
||||||
|
return DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { version, windows } = JSON.parse(raw) as WindowsLS;
|
||||||
|
if (!version || CURRENT_WINDOWS_VERSION > version) {
|
||||||
|
return DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-debugger
|
||||||
|
const out = (windows as Omit<WindowProps, 'content'>[])
|
||||||
|
.filter(x => DEFAULT.find(def => def.id === x.id))
|
||||||
|
.map(x => {
|
||||||
|
const content = DEFAULT.find(def => def.id === x.id)?.content;
|
||||||
|
return { ...x, content: content! };
|
||||||
|
});
|
||||||
|
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MapInterface = () => {
|
||||||
|
const [items, setItems] = useState<WindowProps[]>(restoreWindowsFromLS);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WindowManager
|
||||||
|
windows={items}
|
||||||
|
dragSelector=".react-grid-dragHandleExample"
|
||||||
|
onChange={x => {
|
||||||
|
saveWindowsToLS(x);
|
||||||
|
setItems(x);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
.GridLayoutWrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.GridLayout {
|
|
||||||
width: 100%;
|
|
||||||
height: 100% !important;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
pointer-events: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global {
|
|
||||||
.react-resizable-handle::after {
|
|
||||||
border-color: #696969 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-grid-placeholder {
|
|
||||||
background-color: rgba(147, 147, 147, 0.3);
|
|
||||||
//filter: blur(5px);
|
|
||||||
border: 2px dashed #b6b6b6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-grid-item {
|
|
||||||
transition-property: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-grid-item.cssTransforms {
|
|
||||||
transition-property: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import classes from './WidgetsGrid.module.scss';
|
|
||||||
import { ItemCallback, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import usePageVisibility from '@/hooks/Mapper/hooks/usePageVisibility.ts';
|
|
||||||
|
|
||||||
const ResponsiveGridLayout = WidthProvider(Responsive);
|
|
||||||
|
|
||||||
const colSize = 50;
|
|
||||||
const initState = { breakpoints: 100, cols: 2 };
|
|
||||||
|
|
||||||
export type WidgetGridItem = {
|
|
||||||
rightOffset?: number;
|
|
||||||
leftOffset?: number;
|
|
||||||
topOffset?: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
name: string;
|
|
||||||
item: () => React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface WidgetsGridProps {
|
|
||||||
items: WidgetGridItem[];
|
|
||||||
onChange: (items: WidgetGridItem[]) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WidgetsGrid = ({ items, onChange }: WidgetsGridProps) => {
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const [, setKey] = useState(0);
|
|
||||||
const [callRerenderOfGrid, setCallRerenderOfGrid] = useState(0);
|
|
||||||
|
|
||||||
const isTabVisible = usePageVisibility();
|
|
||||||
|
|
||||||
const refAll = useRef({
|
|
||||||
isReady: false,
|
|
||||||
layouts: {
|
|
||||||
lg: [
|
|
||||||
// { i: 'a', w: 4, h: 16, x: 22, y: 0 },
|
|
||||||
// { i: 'b', w: 5, h: 10, x: 17, y: 0 },
|
|
||||||
],
|
|
||||||
} as Layouts,
|
|
||||||
breakpoints: { lg: 100, md: 0, sm: 0, xs: 0, xxs: 0 },
|
|
||||||
cols: { lg: 26, md: 0, sm: 0, xs: 0, xxs: 0 },
|
|
||||||
containerWidth: 0,
|
|
||||||
colsPrev: 26,
|
|
||||||
needPostProcess: false,
|
|
||||||
items: [...items],
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// 1. onLayoutChange (original) not calling when we change x of any widget
|
|
||||||
// 2. setKey need no call rerender for update props
|
|
||||||
const onLayoutChange: ItemCallback = (newItems, _, newItem) => {
|
|
||||||
const updatedItems = newItems.map(item => {
|
|
||||||
const toLeft = (item.x + item.w / 2) / refAll.current.cols.lg <= 0.5;
|
|
||||||
const original = refAll.current.items.find(x => x.name === item.i)!;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...original,
|
|
||||||
width: item.w,
|
|
||||||
height: item.h,
|
|
||||||
leftOffset: toLeft ? item.x : undefined,
|
|
||||||
rightOffset: !toLeft ? refAll.current.cols.lg - (item.x + item.w) : undefined,
|
|
||||||
topOffset: item.y,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const sortedItems = [
|
|
||||||
...updatedItems.filter(x => x.name !== newItem.i),
|
|
||||||
updatedItems.find(x => x.name === newItem.i)!,
|
|
||||||
];
|
|
||||||
|
|
||||||
refAll.current.layouts = {
|
|
||||||
lg: [...newItems.filter(x => x.i !== newItem.i), newItem],
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange(sortedItems);
|
|
||||||
setKey(x => x + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refAll.current.items = [...items];
|
|
||||||
setKey(x => x + 1);
|
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// 1. Unknown why but if we set layout and cols both instantly it not help...
|
|
||||||
// 1.2 it means that we should make report... until we will send new key on window resize
|
|
||||||
useEffect(() => {
|
|
||||||
const updateItems = () => {
|
|
||||||
if (!containerRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { width } = containerRef.current.getBoundingClientRect();
|
|
||||||
const newColsCount = (width - (width % colSize)) / colSize;
|
|
||||||
|
|
||||||
refAll.current.layouts = {
|
|
||||||
lg: refAll.current.items.map(({ name, width, height, rightOffset, leftOffset, topOffset = 0 }) => {
|
|
||||||
return {
|
|
||||||
i: name,
|
|
||||||
x: rightOffset != null ? newColsCount - width - rightOffset : leftOffset ?? 0,
|
|
||||||
y: topOffset,
|
|
||||||
w: width,
|
|
||||||
h: height,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
refAll.current.cols = { lg: newColsCount, md: 0, sm: 0, xs: 0, xxs: 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateContainerWidth = () => {
|
|
||||||
if (!containerRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { width } = containerRef.current.getBoundingClientRect();
|
|
||||||
|
|
||||||
refAll.current.containerWidth = width;
|
|
||||||
const newColsCount = (width - (width % colSize)) / colSize;
|
|
||||||
|
|
||||||
if (width <= 100 || refAll.current.cols.lg === newColsCount) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refAll.current.isReady) {
|
|
||||||
updateItems();
|
|
||||||
setCallRerenderOfGrid(x => x + 1);
|
|
||||||
refAll.current.isReady = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
refAll.current.layouts = {
|
|
||||||
lg: refAll.current.layouts.lg.map(lgEl => {
|
|
||||||
const toLeft = (lgEl.x + lgEl.w / 2) / refAll.current.cols.lg <= 0.5;
|
|
||||||
const next = {
|
|
||||||
...lgEl,
|
|
||||||
x: toLeft ? lgEl.x : newColsCount - (refAll.current.cols.lg - lgEl.x),
|
|
||||||
};
|
|
||||||
return next;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
refAll.current.cols = { lg: newColsCount, md: 0, sm: 0, xs: 0, xxs: 0 };
|
|
||||||
setCallRerenderOfGrid(x => x + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
setTimeout(() => updateContainerWidth(), 100);
|
|
||||||
|
|
||||||
const withRerender = () => {
|
|
||||||
updateContainerWidth();
|
|
||||||
setCallRerenderOfGrid(x => x + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('resize', withRerender);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', withRerender);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const isNotSet = initState.cols === refAll.current.cols.lg;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={containerRef} className={clsx(classes.GridLayoutWrapper, 'relative p-4')}>
|
|
||||||
{!isNotSet && isTabVisible && (
|
|
||||||
<ResponsiveGridLayout
|
|
||||||
key={callRerenderOfGrid}
|
|
||||||
className={classes.GridLayout}
|
|
||||||
layouts={refAll.current.layouts}
|
|
||||||
breakpoints={refAll.current.breakpoints}
|
|
||||||
cols={refAll.current.cols}
|
|
||||||
rowHeight={30}
|
|
||||||
width={refAll.current.containerWidth}
|
|
||||||
preventCollision={true}
|
|
||||||
compactType={null}
|
|
||||||
allowOverlap
|
|
||||||
onDragStop={onLayoutChange}
|
|
||||||
onResizeStop={onLayoutChange}
|
|
||||||
// onResizeStart={onLayoutChange}
|
|
||||||
// onDragStart={onLayoutChange}
|
|
||||||
isBounded
|
|
||||||
containerPadding={[0, 0]}
|
|
||||||
resizeHandles={['sw', 'se']}
|
|
||||||
draggableHandle=".react-grid-dragHandleExample"
|
|
||||||
>
|
|
||||||
{refAll.current.items.map(x => (
|
|
||||||
<div key={x.name} className="grid-item">
|
|
||||||
{x.item()}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</ResponsiveGridLayout>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './WidgetsGrid';
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import React, { useState, useRef, useEffect, useMemo } from 'react';
|
import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
||||||
import styles from './WindowManager.module.scss';
|
import styles from './WindowManager.module.scss';
|
||||||
|
import debounce from 'lodash.debounce';
|
||||||
|
import { WindowProps } from '@/hooks/Mapper/components/ui-kit/WindowManager/types.ts';
|
||||||
|
|
||||||
const MIN_WINDOW_SIZE = 100;
|
const MIN_WINDOW_SIZE = 100;
|
||||||
const SNAP_THRESHOLD = 10;
|
const SNAP_THRESHOLD = 10;
|
||||||
@@ -17,14 +19,6 @@ export const DefaultWindowState = {
|
|||||||
height: 0,
|
height: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WindowProps = {
|
|
||||||
id: number | string;
|
|
||||||
content: (w: WindowProps) => React.ReactNode;
|
|
||||||
position: { x: number; y: number };
|
|
||||||
size: { width: number; height: number };
|
|
||||||
zIndex: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getWindowsBySides(windows: WindowProps[], containerWidth: number, containerHeight: number) {
|
function getWindowsBySides(windows: WindowProps[], containerWidth: number, containerHeight: number) {
|
||||||
const centerX = containerWidth / 2;
|
const centerX = containerWidth / 2;
|
||||||
const centerY = containerHeight / 2;
|
const centerY = containerHeight / 2;
|
||||||
@@ -86,9 +80,10 @@ export const WindowWrapper = ({ onResize, onDrag, ...window }: WindowWrapperProp
|
|||||||
type WindowManagerProps = {
|
type WindowManagerProps = {
|
||||||
windows: WindowProps[];
|
windows: WindowProps[];
|
||||||
dragSelector?: string;
|
dragSelector?: string;
|
||||||
|
onChange?(windows: WindowProps[]): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WindowManager: React.FC<WindowManagerProps> = ({ windows: initialWindows, dragSelector }) => {
|
export const WindowManager: React.FC<WindowManagerProps> = ({ windows: initialWindows, dragSelector, onChange }) => {
|
||||||
const [windows, setWindows] = useState(
|
const [windows, setWindows] = useState(
|
||||||
initialWindows.map((window, index) => ({
|
initialWindows.map((window, index) => ({
|
||||||
...window,
|
...window,
|
||||||
@@ -102,11 +97,17 @@ export const WindowManager: React.FC<WindowManagerProps> = ({ windows: initialWi
|
|||||||
const startMousePositionRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
const startMousePositionRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||||
const startWindowStateRef = useRef<{ x: number; y: number; width: number; height: number }>(DefaultWindowState);
|
const startWindowStateRef = useRef<{ x: number; y: number; width: number; height: number }>(DefaultWindowState);
|
||||||
|
|
||||||
const ref = useRef({ windows });
|
const ref = useRef({ windows, onChange });
|
||||||
ref.current = { windows };
|
ref.current = { windows, onChange };
|
||||||
|
|
||||||
const refPrevSize = useRef({ w: 0, h: 0 });
|
const refPrevSize = useRef({ w: 0, h: 0 });
|
||||||
|
|
||||||
|
const onDebouncedChange = useMemo(() => {
|
||||||
|
return debounce(() => {
|
||||||
|
ref.current.onChange?.(ref.current.windows);
|
||||||
|
}, 20);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleMouseDown = (
|
const handleMouseDown = (
|
||||||
e: React.MouseEvent,
|
e: React.MouseEvent,
|
||||||
windowId: string | number,
|
windowId: string | number,
|
||||||
@@ -313,17 +314,20 @@ export const WindowManager: React.FC<WindowManagerProps> = ({ windows: initialWi
|
|||||||
return window;
|
return window;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onDebouncedChange();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = useCallback(() => {
|
||||||
activeWindowIdRef.current = null;
|
activeWindowIdRef.current = null;
|
||||||
actionTypeRef.current = null;
|
actionTypeRef.current = null;
|
||||||
resizeDirectionRef.current = null;
|
resizeDirectionRef.current = null;
|
||||||
|
|
||||||
|
onDebouncedChange();
|
||||||
window.removeEventListener('mousemove', handleMouseMove);
|
window.removeEventListener('mousemove', handleMouseMove);
|
||||||
window.removeEventListener('mouseup', handleMouseUp);
|
window.removeEventListener('mouseup', handleMouseUp);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
// Handle resize of the container and reposition windows
|
// Handle resize of the container and reposition windows
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -345,40 +349,49 @@ export const WindowManager: React.FC<WindowManagerProps> = ({ windows: initialWi
|
|||||||
|
|
||||||
setWindows(w => {
|
setWindows(w => {
|
||||||
return w.map(x => {
|
return w.map(x => {
|
||||||
|
let next = { ...x };
|
||||||
|
|
||||||
if (right.some(r => r.id === x.id)) {
|
if (right.some(r => r.id === x.id)) {
|
||||||
return {
|
next = {
|
||||||
...x,
|
...next,
|
||||||
position: {
|
position: {
|
||||||
...x.position,
|
...next.position,
|
||||||
x: x.position.x + deltaX,
|
x: next.position.x + deltaX,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return x;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setWindows(w => {
|
|
||||||
return w.map(x => {
|
|
||||||
if (bottom.some(r => r.id === x.id)) {
|
if (bottom.some(r => r.id === x.id)) {
|
||||||
return {
|
next = {
|
||||||
...x,
|
...next,
|
||||||
position: {
|
position: {
|
||||||
...x.position,
|
...next.position,
|
||||||
y: x.position.y + deltaY,
|
y: next.position.y + deltaY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
if (next.position.x + next.size.width > container.clientWidth - SNAP_GAP) {
|
||||||
|
next.position.x = container.clientWidth - next.size.width - SNAP_GAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next.position.y + next.size.height > container.clientHeight - SNAP_GAP) {
|
||||||
|
next.position.y = container.clientHeight - next.size.height - SNAP_GAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onDebouncedChange();
|
||||||
|
|
||||||
refPrevSize.current = { w: container.clientWidth, h: container.clientHeight };
|
refPrevSize.current = { w: container.clientWidth, h: container.clientHeight };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tid = setTimeout(handleResize, 10);
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
return () => {
|
return () => {
|
||||||
|
clearTimeout(tid);
|
||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', handleResize);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export type WindowProps = {
|
export type WindowProps = {
|
||||||
id: number;
|
id: string | number;
|
||||||
content: (w: WindowProps) => React.ReactNode;
|
content: (w: WindowProps) => React.ReactNode;
|
||||||
position: { x: number; y: number };
|
position: { x: number; y: number };
|
||||||
size: { width: number; height: number };
|
size: { width: number; height: number };
|
||||||
|
|||||||
Reference in New Issue
Block a user