mirror of https://github.com/buster-so/buster.git
minor update to dashboard grid and memoizing
This commit is contained in:
parent
5456561734
commit
31b3116e52
|
@ -2,7 +2,8 @@
|
|||
|
||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useMemoizedFn, useMount, useMouse } from '@/hooks';
|
||||
import { useMouse } from '@/hooks/useMouse';
|
||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { BusterSortableItemDragContainer } from './_BusterSortableItemDragContainer';
|
||||
import type { ResizeableGridDragItem } from './interfaces';
|
||||
|
@ -33,8 +34,8 @@ export const BusterResizeColumns: React.FC<ContainerProps> = ({
|
|||
const mouse = useMouse({ moveThrottleMs: 50, disabled: readOnly || !over });
|
||||
const [stagedLayoutColumns, setStagedLayoutColumns] = useState<number[]>(() => columnSizes || []);
|
||||
|
||||
const canResize = useMemo(() => items.length > 1 && items.length < 4, [items.length]);
|
||||
const isDropzoneActives = useMemo(() => !!over?.id && canResize, [over?.id, canResize]);
|
||||
const canResize = items.length > 1 && items.length < 4;
|
||||
const isDropzoneActives = !!over?.id && canResize;
|
||||
|
||||
const insertPosition = useMemoizedFn((itemId: string, _index: number, mouseLeft: number) => {
|
||||
const movedIndex = _index;
|
||||
|
@ -90,14 +91,6 @@ export const BusterResizeColumns: React.FC<ContainerProps> = ({
|
|||
onRowLayoutChange(newColumnSpans, rowId);
|
||||
});
|
||||
|
||||
const onDragEnd = useMemoizedFn(() => {
|
||||
//Optional: Add any additional drag end logic
|
||||
});
|
||||
|
||||
const onDragStart = useMemoizedFn(() => {
|
||||
// Optional: Add any additional drag start logic
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEqual(stagedLayoutColumns, columnSizes)) {
|
||||
setStagedLayoutColumns(columnSizes || []);
|
||||
|
@ -113,8 +106,8 @@ export const BusterResizeColumns: React.FC<ContainerProps> = ({
|
|||
<BusterResizeColumnsSplitPanes
|
||||
columnSpans={stagedLayoutColumns || []}
|
||||
allowResize={!readOnly && canResize}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
// onDragStart={onDragStart}
|
||||
// onDragEnd={onDragEnd}
|
||||
onChange={onChangeLayout}>
|
||||
{items.map((item, index) => (
|
||||
<div
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import clamp from 'lodash/clamp';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { useDebounceFn, useMemoizedFn, useUpdateLayoutEffect } from '@/hooks';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useDebounceFn, useUpdateLayoutEffect } from '@/hooks';
|
||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import { BusterNewItemDropzone } from './_BusterBusterNewItemDropzone';
|
||||
import { BusterResizeColumns } from './BusterResizeColumns';
|
||||
|
@ -21,13 +22,13 @@ export const BusterResizeRows: React.FC<{
|
|||
const [sizes, setSizes] = useState<number[]>(rows.map((r) => r.rowHeight ?? MIN_ROW_HEIGHT));
|
||||
|
||||
const { run: handleRowLayoutChangeDebounced } = useDebounceFn(
|
||||
useMemoizedFn((sizes: number[]) => {
|
||||
(sizes: number[]) => {
|
||||
const newRows = rows.map((r, index) => ({
|
||||
...r,
|
||||
rowHeight: sizes[index]
|
||||
}));
|
||||
onRowLayoutChange(newRows);
|
||||
}),
|
||||
},
|
||||
{ wait: 375 }
|
||||
);
|
||||
|
||||
|
@ -124,7 +125,7 @@ const ResizeRowHandle: React.FC<{
|
|||
const showDropzone = !!over?.id && !hideDropzone;
|
||||
const isDropzoneActive = showDropzone && isOver;
|
||||
|
||||
const handler = useMemoizedFn((mouseDownEvent: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const handler = (mouseDownEvent: React.MouseEvent<HTMLButtonElement>) => {
|
||||
if (typeof index !== 'number') return;
|
||||
|
||||
const startPosition = mouseDownEvent.pageY;
|
||||
|
@ -147,17 +148,15 @@ const ResizeRowHandle: React.FC<{
|
|||
|
||||
document.body.addEventListener('mousemove', onMouseMove);
|
||||
document.body.addEventListener('mouseup', onMouseUp, { once: true });
|
||||
});
|
||||
};
|
||||
|
||||
const onMouseDown = top ? undefined : handler;
|
||||
|
||||
const memoizedStyle = useMemo(() => {
|
||||
return {
|
||||
zIndex: 1,
|
||||
bottom: !top ? -4 : -4,
|
||||
transform: !top ? 'translateY(100%)' : 'translateY(100%)'
|
||||
};
|
||||
}, [top]);
|
||||
const style: React.CSSProperties = {
|
||||
zIndex: 1,
|
||||
bottom: !top ? -4 : -4,
|
||||
transform: !top ? 'translateY(100%)' : 'translateY(100%)'
|
||||
};
|
||||
|
||||
const showActive = (active || isDropzoneActive) && !readOnly;
|
||||
|
||||
|
@ -172,7 +171,7 @@ const ResizeRowHandle: React.FC<{
|
|||
'h-1 w-full rounded-sm transition-colors duration-200 ease-in-out select-none',
|
||||
!top && 'dragger absolute'
|
||||
)}
|
||||
style={memoizedStyle}
|
||||
style={style}
|
||||
onMouseDown={onMouseDown}
|
||||
/>
|
||||
<div
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from '@dnd-kit/core';
|
||||
import { arrayMove } from '@dnd-kit/sortable';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { use, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { useMemoizedFn, useUpdateEffect } from '@/hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
@ -74,70 +74,76 @@ export const BusterResizeableGrid: React.FC<{
|
|||
|
||||
const sensors = useSensors(useSensor(PointerSensor, pointerSensors));
|
||||
|
||||
const collisionDetectionStrategy: CollisionDetection = useMemoizedFn((args) => {
|
||||
if (activeId && rows.some((row) => row.id === activeId)) {
|
||||
return closestCenter({
|
||||
...args,
|
||||
droppableContainers: args.droppableContainers.filter((container) =>
|
||||
rows.map((v) => v.id).includes(container.id as string)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// Start by finding any intersecting droppable
|
||||
const pointerIntersections = pointerWithin(args);
|
||||
const intersections =
|
||||
pointerIntersections.length > 0
|
||||
? // If there are droppables intersecting with the pointer, return those
|
||||
pointerIntersections
|
||||
: []; //rectIntersection(args);
|
||||
|
||||
let overId = getFirstCollision(intersections, 'id');
|
||||
|
||||
if (overId != null) {
|
||||
if (rows.some((row) => row.id === overId)) {
|
||||
const containerItems = rows.find((row) => row.id === overId)?.items || [];
|
||||
|
||||
// If a container is matched and it contains items (columns 'A', 'B', 'C')
|
||||
if (containerItems.length > 0) {
|
||||
// Return the closest droppable within that container
|
||||
overId = closestCenter({
|
||||
...args,
|
||||
droppableContainers: args.droppableContainers.filter(
|
||||
(container) =>
|
||||
container.id !== overId &&
|
||||
containerItems.map((v) => v.id).includes(container.id as string)
|
||||
)
|
||||
})[0]?.id;
|
||||
}
|
||||
const collisionDetectionStrategy: CollisionDetection = useCallback(
|
||||
(args) => {
|
||||
if (activeId && rows.some((row) => row.id === activeId)) {
|
||||
return closestCenter({
|
||||
...args,
|
||||
droppableContainers: args.droppableContainers.filter((container) =>
|
||||
rows.map((v) => v.id).includes(container.id as string)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
lastOverId.current = overId as string;
|
||||
// Start by finding any intersecting droppable
|
||||
const pointerIntersections = pointerWithin(args);
|
||||
const intersections =
|
||||
pointerIntersections.length > 0
|
||||
? // If there are droppables intersecting with the pointer, return those
|
||||
pointerIntersections
|
||||
: []; //rectIntersection(args);
|
||||
|
||||
return [{ id: overId }];
|
||||
}
|
||||
let overId = getFirstCollision(intersections, 'id');
|
||||
|
||||
// When a draggable item moves to a new container, the layout may shift
|
||||
// and the `overId` may become `null`. We manually set the cached `lastOverId`
|
||||
// to the id of the draggable item that was moved to the new container, otherwise
|
||||
// the previous `overId` will be returned which can cause items to incorrectly shift positions
|
||||
if (recentlyMovedToNewContainer.current) {
|
||||
lastOverId.current = activeId;
|
||||
}
|
||||
if (overId != null) {
|
||||
if (rows.some((row) => row.id === overId)) {
|
||||
const containerItems = rows.find((row) => row.id === overId)?.items || [];
|
||||
|
||||
// If no droppable is matched, return the last match
|
||||
return lastOverId.current ? [{ id: lastOverId.current }] : [];
|
||||
});
|
||||
// If a container is matched and it contains items (columns 'A', 'B', 'C')
|
||||
if (containerItems.length > 0) {
|
||||
// Return the closest droppable within that container
|
||||
overId = closestCenter({
|
||||
...args,
|
||||
droppableContainers: args.droppableContainers.filter(
|
||||
(container) =>
|
||||
container.id !== overId &&
|
||||
containerItems.map((v) => v.id).includes(container.id as string)
|
||||
)
|
||||
})[0]?.id;
|
||||
}
|
||||
}
|
||||
|
||||
const findContainer = useMemoizedFn((id: string) => {
|
||||
if (rows.some((row) => row.id === id)) {
|
||||
return id;
|
||||
}
|
||||
lastOverId.current = overId as string;
|
||||
|
||||
return rows.find((row) => row.items.some((item) => item.id === id))?.id;
|
||||
});
|
||||
return [{ id: overId }];
|
||||
}
|
||||
|
||||
const onDragCancel = useMemoizedFn(() => {
|
||||
// When a draggable item moves to a new container, the layout may shift
|
||||
// and the `overId` may become `null`. We manually set the cached `lastOverId`
|
||||
// to the id of the draggable item that was moved to the new container, otherwise
|
||||
// the previous `overId` will be returned which can cause items to incorrectly shift positions
|
||||
if (recentlyMovedToNewContainer.current) {
|
||||
lastOverId.current = activeId;
|
||||
}
|
||||
|
||||
// If no droppable is matched, return the last match
|
||||
return lastOverId.current ? [{ id: lastOverId.current }] : [];
|
||||
},
|
||||
[activeId, rows]
|
||||
);
|
||||
|
||||
const findContainer = useCallback(
|
||||
(id: string) => {
|
||||
if (rows.some((row) => row.id === id)) {
|
||||
return id;
|
||||
}
|
||||
|
||||
return rows.find((row) => row.items.some((item) => item.id === id))?.id;
|
||||
},
|
||||
[rows]
|
||||
);
|
||||
|
||||
const onDragCancel = useCallback(() => {
|
||||
if (serverRows) {
|
||||
// Reset items to their original state in case items have been
|
||||
// Dragged across containers
|
||||
|
@ -145,17 +151,20 @@ export const BusterResizeableGrid: React.FC<{
|
|||
}
|
||||
|
||||
setActiveId(null);
|
||||
});
|
||||
}, [serverRows, onRowLayoutChangePreflight]);
|
||||
|
||||
const onDragStart = useMemoizedFn(({ active }: DragStartEvent) => {
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = '* { cursor: grabbing; }';
|
||||
document.head.appendChild(style);
|
||||
styleRef.current = style;
|
||||
setActiveId(active.id as string);
|
||||
onStartDrag?.({ id: active.id as string });
|
||||
isAnimating.current = true;
|
||||
});
|
||||
const onDragStart = useCallback(
|
||||
({ active }: DragStartEvent) => {
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = '* { cursor: grabbing; }';
|
||||
document.head.appendChild(style);
|
||||
styleRef.current = style;
|
||||
setActiveId(active.id as string);
|
||||
onStartDrag?.({ id: active.id as string });
|
||||
isAnimating.current = true;
|
||||
},
|
||||
[onStartDrag]
|
||||
);
|
||||
|
||||
const onDragEnd = useMemoizedFn(
|
||||
({ over, active, delta, activatorEvent, collisions }: DragEndEvent) => {
|
||||
|
|
|
@ -200,48 +200,44 @@ const LeavingDialog: React.FC<{
|
|||
okText: string;
|
||||
canceling: boolean;
|
||||
okaying: boolean;
|
||||
}> = React.memo(
|
||||
({
|
||||
onClose,
|
||||
isOpen,
|
||||
okaying,
|
||||
canceling,
|
||||
noCallback,
|
||||
yesCallback,
|
||||
title,
|
||||
description,
|
||||
okText,
|
||||
cancelText
|
||||
}) => {
|
||||
const disableButtons = okaying || canceling;
|
||||
}> = ({
|
||||
onClose,
|
||||
isOpen,
|
||||
okaying,
|
||||
canceling,
|
||||
noCallback,
|
||||
yesCallback,
|
||||
title,
|
||||
description,
|
||||
okText,
|
||||
cancelText
|
||||
}) => {
|
||||
const disableButtons = okaying || canceling;
|
||||
|
||||
const memoizedHeader = useMemo(() => {
|
||||
return { title, description };
|
||||
}, [title, description]);
|
||||
const memoizedHeader = useMemo(() => {
|
||||
return { title, description };
|
||||
}, [title, description]);
|
||||
|
||||
const memoizedFooter = useMemo(() => {
|
||||
return {
|
||||
primaryButton: {
|
||||
text: cancelText,
|
||||
onClick: noCallback,
|
||||
loading: canceling,
|
||||
disabled: disableButtons
|
||||
},
|
||||
secondaryButton: {
|
||||
text: okText,
|
||||
onClick: yesCallback,
|
||||
loading: okaying,
|
||||
disabled: disableButtons
|
||||
}
|
||||
};
|
||||
}, [okaying, canceling, disableButtons, noCallback, yesCallback, cancelText, okText]);
|
||||
const memoizedFooter = useMemo(() => {
|
||||
return {
|
||||
primaryButton: {
|
||||
text: cancelText,
|
||||
onClick: noCallback,
|
||||
loading: canceling,
|
||||
disabled: disableButtons
|
||||
},
|
||||
secondaryButton: {
|
||||
text: okText,
|
||||
onClick: yesCallback,
|
||||
loading: okaying,
|
||||
disabled: disableButtons
|
||||
}
|
||||
};
|
||||
}, [okaying, canceling, disableButtons, noCallback, yesCallback, cancelText, okText]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppModal open={isOpen} onClose={onClose} header={memoizedHeader} footer={memoizedFooter} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AppModal open={isOpen} onClose={onClose} header={memoizedHeader} footer={memoizedFooter} />
|
||||
);
|
||||
};
|
||||
|
||||
LeavingDialog.displayName = 'LeavingDialog';
|
||||
|
|
Loading…
Reference in New Issue