mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-27 00:19:55 +03:00
Initial implementation
This commit is contained in:
parent
29c1d4ba45
commit
968e6c9e35
|
@ -1,7 +1,32 @@
|
||||||
import React, { useCallback, useLayoutEffect, useRef } from 'react';
|
import React, {
|
||||||
|
forwardRef,
|
||||||
|
ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useLayoutEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
import { PerformAction } from '@redux-devtools/core';
|
import { PerformAction } from '@redux-devtools/core';
|
||||||
import { StylingFunction } from 'react-base16-styling';
|
import { StylingFunction } from 'react-base16-styling';
|
||||||
|
import {
|
||||||
|
closestCenter,
|
||||||
|
DndContext,
|
||||||
|
DragEndEvent,
|
||||||
|
DragOverlay,
|
||||||
|
DragStartEvent,
|
||||||
|
KeyboardSensor,
|
||||||
|
PointerSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import {
|
||||||
|
SortableContext,
|
||||||
|
sortableKeyboardCoordinates,
|
||||||
|
useSortable,
|
||||||
|
verticalListSortingStrategy,
|
||||||
|
} from '@dnd-kit/sortable';
|
||||||
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
import ActionListRow from './ActionListRow';
|
import ActionListRow from './ActionListRow';
|
||||||
import ActionListHeader from './ActionListHeader';
|
import ActionListHeader from './ActionListHeader';
|
||||||
|
|
||||||
|
@ -65,9 +90,13 @@ export default function ActionListFunction<A extends Action<unknown>>({
|
||||||
onSweep,
|
onSweep,
|
||||||
onJumpToState,
|
onJumpToState,
|
||||||
lastActionId,
|
lastActionId,
|
||||||
|
onReorderAction,
|
||||||
}: Props<A>) {
|
}: Props<A>) {
|
||||||
const nodeRef = useRef<HTMLDivElement | null>(null);
|
const nodeRef = useRef<HTMLDivElement | null>(null);
|
||||||
const prevLastActionId = useRef<number | undefined>();
|
const prevLastActionId = useRef<number | undefined>();
|
||||||
|
const [activeDragActionId, setActiveDragActionId] = useState<number | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (nodeRef.current && prevLastActionId.current !== lastActionId) {
|
if (nodeRef.current && prevLastActionId.current !== lastActionId) {
|
||||||
|
@ -88,6 +117,28 @@ export default function ActionListFunction<A extends Action<unknown>>({
|
||||||
nodeRef.current = node;
|
nodeRef.current = node;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(PointerSensor),
|
||||||
|
useSensor(KeyboardSensor, {
|
||||||
|
coordinateGetter: sortableKeyboardCoordinates,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDragStart = useCallback(({ active }: DragStartEvent) => {
|
||||||
|
setActiveDragActionId(active.id as number);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDragEnd = useCallback(
|
||||||
|
({ active, over }: DragEndEvent) => {
|
||||||
|
if (over && active.id !== over.id) {
|
||||||
|
onReorderAction(active.id as number, over.id as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
setActiveDragActionId(null);
|
||||||
|
},
|
||||||
|
[onReorderAction],
|
||||||
|
);
|
||||||
|
|
||||||
const lowerSearchValue = searchValue && searchValue.toLowerCase();
|
const lowerSearchValue = searchValue && searchValue.toLowerCase();
|
||||||
const filteredActionIds = searchValue
|
const filteredActionIds = searchValue
|
||||||
? actionIds.filter(
|
? actionIds.filter(
|
||||||
|
@ -98,6 +149,35 @@ export default function ActionListFunction<A extends Action<unknown>>({
|
||||||
)
|
)
|
||||||
: actionIds;
|
: actionIds;
|
||||||
|
|
||||||
|
function renderActionListRow(actionId: number) {
|
||||||
|
return (
|
||||||
|
<ActionListRow
|
||||||
|
styling={styling}
|
||||||
|
actionId={actionId}
|
||||||
|
isInitAction={!actionId}
|
||||||
|
isSelected={
|
||||||
|
(startActionId !== null &&
|
||||||
|
actionId >= startActionId &&
|
||||||
|
actionId <= (selectedActionId as number)) ||
|
||||||
|
actionId === selectedActionId
|
||||||
|
}
|
||||||
|
isInFuture={
|
||||||
|
actionIds.indexOf(actionId) > actionIds.indexOf(currentActionId)
|
||||||
|
}
|
||||||
|
onSelect={(e: React.MouseEvent<HTMLDivElement>) =>
|
||||||
|
onSelect(e, actionId)
|
||||||
|
}
|
||||||
|
timestamps={getTimestamps(actions, actionIds, actionId)}
|
||||||
|
action={actions[actionId].action}
|
||||||
|
onToggleClick={() => onToggleAction(actionId)}
|
||||||
|
onJumpClick={() => onJumpToState(actionId)}
|
||||||
|
onCommitClick={() => onCommit()}
|
||||||
|
hideActionButtons={hideActionButtons}
|
||||||
|
isSkipped={skippedActionIds.indexOf(actionId) !== -1}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key="actionList"
|
key="actionList"
|
||||||
|
@ -121,35 +201,58 @@ export default function ActionListFunction<A extends Action<unknown>>({
|
||||||
data-testid="actionListRows"
|
data-testid="actionListRows"
|
||||||
{...styling('actionListRows')}
|
{...styling('actionListRows')}
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
|
>
|
||||||
|
<DndContext
|
||||||
|
sensors={sensors}
|
||||||
|
collisionDetection={closestCenter}
|
||||||
|
onDragStart={handleDragStart}
|
||||||
|
onDragEnd={handleDragEnd}
|
||||||
|
>
|
||||||
|
<SortableContext
|
||||||
|
items={filteredActionIds}
|
||||||
|
strategy={verticalListSortingStrategy}
|
||||||
>
|
>
|
||||||
{filteredActionIds.map((actionId) => (
|
{filteredActionIds.map((actionId) => (
|
||||||
<ActionListRow
|
<SortableItem key={actionId} actionId={actionId}>
|
||||||
key={actionId}
|
{renderActionListRow(actionId)}
|
||||||
styling={styling}
|
</SortableItem>
|
||||||
actionId={actionId}
|
|
||||||
isInitAction={!actionId}
|
|
||||||
isSelected={
|
|
||||||
(startActionId !== null &&
|
|
||||||
actionId >= startActionId &&
|
|
||||||
actionId <= (selectedActionId as number)) ||
|
|
||||||
actionId === selectedActionId
|
|
||||||
}
|
|
||||||
isInFuture={
|
|
||||||
actionIds.indexOf(actionId) > actionIds.indexOf(currentActionId)
|
|
||||||
}
|
|
||||||
onSelect={(e: React.MouseEvent<HTMLDivElement>) =>
|
|
||||||
onSelect(e, actionId)
|
|
||||||
}
|
|
||||||
timestamps={getTimestamps(actions, actionIds, actionId)}
|
|
||||||
action={actions[actionId].action}
|
|
||||||
onToggleClick={() => onToggleAction(actionId)}
|
|
||||||
onJumpClick={() => onJumpToState(actionId)}
|
|
||||||
onCommitClick={() => onCommit()}
|
|
||||||
hideActionButtons={hideActionButtons}
|
|
||||||
isSkipped={skippedActionIds.indexOf(actionId) !== -1}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
|
</SortableContext>
|
||||||
|
<DragOverlay>
|
||||||
|
{activeDragActionId ? (
|
||||||
|
<Item>{renderActionListRow(activeDragActionId)}</Item>
|
||||||
|
) : null}
|
||||||
|
</DragOverlay>
|
||||||
|
</DndContext>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SortableItemProps {
|
||||||
|
readonly children: ReactNode;
|
||||||
|
readonly actionId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SortableItem({ children, actionId }: SortableItemProps) {
|
||||||
|
const { attributes, listeners, setNodeRef, transform, transition } =
|
||||||
|
useSortable({ id: actionId });
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
transform: CSS.Transform.toString(transform),
|
||||||
|
transition,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Item ref={setNodeRef} style={style} {...attributes} {...listeners}>
|
||||||
|
{children}
|
||||||
|
</Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item = forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
||||||
|
>(function Item({ ...props }, ref) {
|
||||||
|
return <div {...props} ref={ref} />;
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user