feat(ui): split dnd overlay to separate component

This reduces top-level rerenders when zooming in and out on workflow editor
This commit is contained in:
psychedelicious 2024-01-01 12:38:20 +11:00 committed by Kent Keirsey
parent 5d4610d981
commit 7eb79266c4
2 changed files with 65 additions and 53 deletions

View File

@ -1,28 +1,19 @@
import {
DragOverlay,
MouseSensor,
TouchSensor,
useSensor,
useSensors,
} from '@dnd-kit/core';
import { MouseSensor, TouchSensor, useSensor, useSensors } from '@dnd-kit/core';
import { logger } from 'app/logging/logger';
import { dndDropped } from 'app/store/middleware/listenerMiddleware/listeners/imageDropped';
import { useAppDispatch } from 'app/store/storeHooks';
import { parseify } from 'common/util/serialize';
import { useScaledModifer } from 'features/dnd/hooks/useScaledCenteredModifer';
import DndOverlay from 'features/dnd/components/DndOverlay';
import type {
DragEndEvent,
DragStartEvent,
TypesafeDraggableData,
} from 'features/dnd/types';
import { customPointerWithin } from 'features/dnd/util/customPointerWithin';
import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
import type { CSSProperties, PropsWithChildren } from 'react';
import { memo, useCallback, useMemo, useState } from 'react';
import type { PropsWithChildren } from 'react';
import { memo, useCallback, useState } from 'react';
import { DndContextTypesafe } from './DndContextTypesafe';
import DragPreview from './DragPreview';
const AppDndContext = (props: PropsWithChildren) => {
const [activeDragData, setActiveDragData] =
@ -77,9 +68,6 @@ const AppDndContext = (props: PropsWithChildren) => {
const sensors = useSensors(mouseSensor, touchSensor);
const scaledModifier = useScaledModifer();
const modifiers = useMemo(() => [scaledModifier], [scaledModifier]);
return (
<DndContextTypesafe
onDragStart={handleDragStart}
@ -89,45 +77,9 @@ const AppDndContext = (props: PropsWithChildren) => {
autoScroll={false}
>
{props.children}
<DragOverlay
dropAnimation={null}
modifiers={modifiers}
style={dragOverlayStyles}
>
<AnimatePresence>
{activeDragData && (
<motion.div
layout
key="overlay-drag-image"
initial={initial}
animate={animate}
>
<DragPreview dragData={activeDragData} />
</motion.div>
)}
</AnimatePresence>
</DragOverlay>
<DndOverlay activeDragData={activeDragData} />
</DndContextTypesafe>
);
};
export default memo(AppDndContext);
const dragOverlayStyles: CSSProperties = {
width: 'min-content',
height: 'min-content',
cursor: 'grabbing',
userSelect: 'none',
// expand overlay to prevent cursor from going outside it and displaying
padding: '10rem',
};
const initial: AnimationProps['initial'] = {
opacity: 0,
scale: 0.7,
};
const animate: AnimationProps['animate'] = {
opacity: 1,
scale: 1,
transition: { duration: 0.1 },
};

View File

@ -0,0 +1,60 @@
import { DragOverlay } from '@dnd-kit/core';
import { useScaledModifer } from 'features/dnd/hooks/useScaledCenteredModifer';
import type { TypesafeDraggableData } from 'features/dnd/types';
import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
import type { CSSProperties } from 'react';
import { memo, useMemo } from 'react';
import DragPreview from './DragPreview';
type DndOverlayProps = {
activeDragData: TypesafeDraggableData | null;
};
const DndOverlay = (props: DndOverlayProps) => {
const scaledModifier = useScaledModifer();
const modifiers = useMemo(() => [scaledModifier], [scaledModifier]);
return (
<DragOverlay
dropAnimation={null}
modifiers={modifiers}
style={dragOverlayStyles}
>
<AnimatePresence>
{props.activeDragData && (
<motion.div
layout
key="overlay-drag-image"
initial={initial}
animate={animate}
>
<DragPreview dragData={props.activeDragData} />
</motion.div>
)}
</AnimatePresence>
</DragOverlay>
);
};
export default memo(DndOverlay);
const dragOverlayStyles: CSSProperties = {
width: 'min-content',
height: 'min-content',
cursor: 'grabbing',
userSelect: 'none',
// expand overlay to prevent cursor from going outside it and displaying
padding: '10rem',
};
const initial: AnimationProps['initial'] = {
opacity: 0,
scale: 0.7,
};
const animate: AnimationProps['animate'] = {
opacity: 1,
scale: 1,
transition: { duration: 0.1 },
};