From 1998c20ecc26f0e2cb24f06077bc01e3dabcaf7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claud=C3=A9ric=20Demers?= Date: Mon, 23 Sep 2024 11:55:05 -0400 Subject: [PATCH] Update `move` utility to accept `event` --- .changeset/move-helper.md | 5 ++ .../react/guides/multiple-sortable-lists.mdx | 12 ++-- .../Sortable/MultipleLists/MultipleLists.tsx | 19 ++--- .../MultipleLists/docs/examples/Guide.jsx | 6 +- .../docs/examples/QuickStart.jsx | 6 +- .../react/Sortable/SortableExample.tsx | 12 +--- .../ReactTinyVirtualListExample.tsx | 8 +-- .../Virtualized/ReactVirtualExample.tsx | 8 +-- .../Virtualized/ReactWindowExample.tsx | 28 +++----- .../docs/examples/ControlledExample.jsx | 6 +- .../react/Sortable/docs/examples/Example.jsx | 6 +- .../src/sortable/OptimisticSortingPlugin.ts | 5 +- packages/helpers/src/move.ts | 72 ++++++++++++------- 13 files changed, 82 insertions(+), 111 deletions(-) create mode 100644 .changeset/move-helper.md diff --git a/.changeset/move-helper.md b/.changeset/move-helper.md new file mode 100644 index 00000000..1549b3db --- /dev/null +++ b/.changeset/move-helper.md @@ -0,0 +1,5 @@ +--- +'@dnd-kit/helpers': patch +--- + +Updated the `move` helper to accept an `event` instead of `source` and `target`. diff --git a/apps/docs/react/guides/multiple-sortable-lists.mdx b/apps/docs/react/guides/multiple-sortable-lists.mdx index a0bd0be3..f3bed326 100644 --- a/apps/docs/react/guides/multiple-sortable-lists.mdx +++ b/apps/docs/react/guides/multiple-sortable-lists.mdx @@ -191,9 +191,7 @@ export function App() { return ( { - const {source, target} = event.operation; - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, eventt)); }} >
@@ -267,14 +265,14 @@ export function App({style = styles}) { if (source?.type === 'column') return; - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { const {source, target} = event.operation; if (event.canceled || source.type !== 'column') return; - setColumnOrder((columns) => move(columns, source, target)); + setColumnOrder((columns) => move(columns, sevent)); }} >
@@ -330,7 +328,7 @@ export function App({style = styles}) { if (source?.type === 'column') return; - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { const {source, target} = event.operation; @@ -344,7 +342,7 @@ export function App({style = styles}) { } if (source.type === 'column') { - setColumnOrder((columns) => move(columns, source, target)); + setColumnOrder((columns) => move(columns, event)); } }} > diff --git a/apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.tsx b/apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.tsx index ee7d8876..257f810c 100644 --- a/apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.tsx +++ b/apps/stories/stories/react/Sortable/MultipleLists/MultipleLists.tsx @@ -56,23 +56,14 @@ export function MultipleLists({ snapshot.current = cloneDeep(items); }} onDragOver={(event) => { - const {source, target} = event.operation; + const {source} = event.operation; - if (!source || !target || source.id === target.id) { - return; - } - - if (source.type === 'column') { + if (source?.type === 'column') { // We can rely on optimistic sorting for columns return; } - if (target.id === source.data.group) { - event.preventDefault(); - return; - } - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { if (event.canceled) { @@ -80,10 +71,10 @@ export function MultipleLists({ return; } - const {source, target} = event.operation; + const {source} = event.operation; if (source?.type === 'column') { - setColumns((columns) => move(columns, source, target)); + setColumns((columns) => move(columns, event)); } }} > diff --git a/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Guide.jsx b/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Guide.jsx index 7b906517..47be5869 100644 --- a/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Guide.jsx +++ b/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/Guide.jsx @@ -27,11 +27,7 @@ export function Guide({ return; } - const {source, target} = event.operation; - - if (source && target) { - setItems((items) => move(items, source, target)); - } + setItems((items) => move(items, event)); }} >
diff --git a/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/QuickStart.jsx b/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/QuickStart.jsx index 72ffea8a..d8d983ca 100644 --- a/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/QuickStart.jsx +++ b/apps/stories/stories/react/Sortable/MultipleLists/docs/examples/QuickStart.jsx @@ -17,11 +17,7 @@ export function Example({style = styles}) { return ( { - const {source, target} = event.operation; - - if (source && target) { - setItems((items) => move(items, source, target)); - } + setItems((items) => move(items, event)); }} >
diff --git a/apps/stories/stories/react/Sortable/SortableExample.tsx b/apps/stories/stories/react/Sortable/SortableExample.tsx index 39e5e4d1..a95dc32a 100644 --- a/apps/stories/stories/react/Sortable/SortableExample.tsx +++ b/apps/stories/stories/react/Sortable/SortableExample.tsx @@ -50,20 +50,12 @@ export function SortableExample({ plugins={debug ? [Debug, ...defaultPreset.plugins] : undefined} modifiers={modifiers} onDragOver={(event) => { - const {source, target} = event.operation; - if (optimistic) return; - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { - const {source, target} = event.operation; - - if (event.canceled) { - return; - } - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} > diff --git a/apps/stories/stories/react/Sortable/Virtualized/ReactTinyVirtualListExample.tsx b/apps/stories/stories/react/Sortable/Virtualized/ReactTinyVirtualListExample.tsx index 640368f8..fcd45a42 100644 --- a/apps/stories/stories/react/Sortable/Virtualized/ReactTinyVirtualListExample.tsx +++ b/apps/stories/stories/react/Sortable/Virtualized/ReactTinyVirtualListExample.tsx @@ -25,13 +25,7 @@ export function ReactTinyVirtualListExample({debug}: Props) { snapshot.current = cloneDeep(items); }} onDragOver={(event) => { - const {source, target} = event.operation; - - if (!source || !target) { - return; - } - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { if (event.canceled) { diff --git a/apps/stories/stories/react/Sortable/Virtualized/ReactVirtualExample.tsx b/apps/stories/stories/react/Sortable/Virtualized/ReactVirtualExample.tsx index 4c783f70..1064cf82 100644 --- a/apps/stories/stories/react/Sortable/Virtualized/ReactVirtualExample.tsx +++ b/apps/stories/stories/react/Sortable/Virtualized/ReactVirtualExample.tsx @@ -41,13 +41,7 @@ export function ReactVirtualExample({debug}: Props) { snapshot.current = cloneDeep(items); }} onDragOver={(event) => { - const {source, target} = event.operation; - - if (!source || !target) { - return; - } - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { if (event.canceled) { diff --git a/apps/stories/stories/react/Sortable/Virtualized/ReactWindowExample.tsx b/apps/stories/stories/react/Sortable/Virtualized/ReactWindowExample.tsx index f1780c0d..a8c2be36 100644 --- a/apps/stories/stories/react/Sortable/Virtualized/ReactWindowExample.tsx +++ b/apps/stories/stories/react/Sortable/Virtualized/ReactWindowExample.tsx @@ -25,13 +25,7 @@ export function ReactWindowExample({debug}: Props) { snapshot.current = cloneDeep(items); }} onDragOver={(event) => { - const {source, target} = event.operation; - - if (!source || !target) { - return; - } - - setItems((items) => move(items, source, target)); + setItems((items) => move(items, event)); }} onDragEnd={(event) => { if (event.canceled) { @@ -54,17 +48,15 @@ export function ReactWindowExample({debug}: Props) { ); } -function Row( - { - data, - index, - style, - }: { - data: UniqueIdentifier[]; - index: number; - style: React.CSSProperties; - } -) { +function Row({ + data, + index, + style, +}: { + data: UniqueIdentifier[]; + index: number; + style: React.CSSProperties; +}) { return ; } diff --git a/apps/stories/stories/react/Sortable/docs/examples/ControlledExample.jsx b/apps/stories/stories/react/Sortable/docs/examples/ControlledExample.jsx index 3d865642..2ae00445 100644 --- a/apps/stories/stories/react/Sortable/docs/examples/ControlledExample.jsx +++ b/apps/stories/stories/react/Sortable/docs/examples/ControlledExample.jsx @@ -11,11 +11,7 @@ export function ControlledExample() { return ( { - const {source, target} = event.operation; - - if (source && target) { - setItems((items) => move(items, source, target)); - } + setItems((items) => move(items, event)); }} >
diff --git a/apps/stories/stories/react/Sortable/docs/examples/Example.jsx b/apps/stories/stories/react/Sortable/docs/examples/Example.jsx index 4137d81c..f871942c 100644 --- a/apps/stories/stories/react/Sortable/docs/examples/Example.jsx +++ b/apps/stories/stories/react/Sortable/docs/examples/Example.jsx @@ -11,11 +11,7 @@ export function Example({style = styles}) { return ( { - const {source, target} = event.operation; - - if (source && target) { - setItems((items) => move(items, source, target)); - } + setItems((items) => move(items, event)); }} >
diff --git a/packages/dom/src/sortable/OptimisticSortingPlugin.ts b/packages/dom/src/sortable/OptimisticSortingPlugin.ts index 8931c999..e71a21ca 100644 --- a/packages/dom/src/sortable/OptimisticSortingPlugin.ts +++ b/packages/dom/src/sortable/OptimisticSortingPlugin.ts @@ -98,7 +98,10 @@ export class OptimisticSortingPlugin extends Plugin { [sourceGroup]: orderedSourceSortables, [targetGroup]: orderedTargetSortables, }; - const newState = move(state, source, target); + const newState = move(state, event); + + if (state === newState) return; + const sourceIndex = newState[targetGroup].indexOf(source.sortable); const targetIndex = newState[targetGroup].indexOf(target.sortable); diff --git a/packages/helpers/src/move.ts b/packages/helpers/src/move.ts index 2ac43d1c..d2e7ef75 100644 --- a/packages/helpers/src/move.ts +++ b/packages/helpers/src/move.ts @@ -1,4 +1,10 @@ -import type {UniqueIdentifier, Draggable, Droppable} from '@dnd-kit/abstract'; +import type { + UniqueIdentifier, + Draggable, + Droppable, + DragDropManager, + DragDropEvents, +} from '@dnd-kit/abstract'; /** * Move an array item to a different position. Returns a new array with the item moved to the new position. @@ -45,13 +51,18 @@ function mutate< T extends Items | Record, U extends Draggable, V extends Droppable, + W extends DragDropManager, >( items: T, - source: U | null, - target: V | null, + event: Parameters< + DragDropEvents['dragover'] | DragDropEvents['dragend'] + >[0], mutation: typeof arrayMove | typeof arraySwap ): T { - if (!source || !target) { + const {source, target, canceled} = event.operation; + + if (!source || !target || canceled || source.id === target.id) { + if ('preventDefault' in event) event.preventDefault(); return items; } @@ -66,30 +77,18 @@ function mutate< return items; } - if (source.manager) { - const {dragOperation} = source.manager; - - // Reconcile optimistic updates - if ( - !dragOperation.canceled && - 'index' in source && - typeof source.index === 'number' - ) { - const projectedSourceIndex = source.index; + // Reconcile optimistic updates + if (!canceled && 'index' in source && typeof source.index === 'number') { + const projectedSourceIndex = source.index; - if (projectedSourceIndex !== sourceIndex) { - return mutation(items, sourceIndex, projectedSourceIndex); - } + if (projectedSourceIndex !== sourceIndex) { + return mutation(items, sourceIndex, projectedSourceIndex); } } return mutation(items, sourceIndex, targetIndex); } - if (source.id === target.id) { - return items; - } - const entries = Object.entries(items); let sourceIndex = -1; @@ -122,7 +121,8 @@ function mutate< if (!source.manager) return items; const {dragOperation} = source.manager; - const position = dragOperation.position.current; + const position = + dragOperation.shape?.current.center ?? dragOperation.position.current; if (targetParent == null) { if (target.id in items) { @@ -137,7 +137,13 @@ function mutate< } } - if (sourceParent == null || targetParent == null) { + if ( + sourceParent == null || + targetParent == null || + (sourceParent === targetParent && sourceIndex === targetIndex) + ) { + if ('preventDefault' in event) event.preventDefault(); + return items; } @@ -171,14 +177,26 @@ export function move< T extends Items | Record, U extends Draggable, V extends Droppable, ->(items: T, source: U | null, target: V | null) { - return mutate(items, source, target, arrayMove); + W extends DragDropManager, +>( + items: T, + event: Parameters< + DragDropEvents['dragover'] | DragDropEvents['dragend'] + >[0] +) { + return mutate(items, event, arrayMove); } export function swap< T extends Items | Record, U extends Draggable, V extends Droppable, ->(items: T, source: U | null, target: V | null) { - return mutate(items, source, target, arraySwap); + W extends DragDropManager, +>( + items: T, + event: Parameters< + DragDropEvents['dragover'] | DragDropEvents['dragend'] + >[0] +) { + return mutate(items, event, arraySwap); }