-
Notifications
You must be signed in to change notification settings - Fork 285
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(playground): re-ordering of messages using dnd (#4936)
- Loading branch information
1 parent
ed6e05e
commit ad27394
Showing
8 changed files
with
503 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from "react"; | ||
import { css } from "@emotion/react"; | ||
|
||
function DragHandle() { | ||
return ( | ||
<button | ||
data-cypress="draggable-handle" | ||
aria-roledescription="draggable" | ||
aria-pressed="false" | ||
aria-disabled="false" | ||
className="button--reset" | ||
css={css` | ||
cursor: grab; | ||
background-color: var(--ac-global-color-grey-200); | ||
border: 1px solid var(--ac-global-color-grey-500); | ||
color: var(--ac-global-text-color-900); | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
padding: var(--ac-global-dimension-size-100) | ||
var(--ac-global-dimension-size-50); | ||
border-radius: var(--ac-global-rounding-small); | ||
overflow: hidden; | ||
`} | ||
> | ||
<svg viewBox="0 0 20 20" width="12" fill="currentColor"> | ||
<path d="M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z"></path> | ||
</svg> | ||
</button> | ||
); | ||
} | ||
|
||
// Use Ref forwarding for DragHandle | ||
const _DragHandle = React.forwardRef(DragHandle); | ||
export { _DragHandle as DragHandle }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
/** | ||
* Copy of @dnd-kit/utils for a needed fix | ||
* TODO: switch to @dnd-kit/helpers once the fix is released | ||
* @src https://github.com/clauderic/dnd-kit/blob/experimental/packages/helpers/src/move.ts | ||
*/ | ||
import type { | ||
DragDropEvents, | ||
DragDropManager, | ||
Draggable, | ||
Droppable, | ||
UniqueIdentifier, | ||
} from "@dnd-kit/abstract"; | ||
|
||
/** | ||
* Move an array item to a different position. Returns a new array with the item moved to the new position. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function arrayMove<T extends any[]>( | ||
array: T, | ||
from: number, | ||
to: number | ||
): T { | ||
if (from === to) { | ||
return array; | ||
} | ||
|
||
const newArray = array.slice() as T; | ||
newArray.splice(to, 0, newArray.splice(from, 1)[0]); | ||
|
||
return newArray; | ||
} | ||
|
||
/** | ||
* Move an array item to a different position. Returns a new array with the item moved to the new position. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function arraySwap<T extends any[]>( | ||
array: T, | ||
from: number, | ||
to: number | ||
): T { | ||
if (from === to) { | ||
return array; | ||
} | ||
|
||
const newArray = array.slice() as T; | ||
const item = newArray[from]; | ||
|
||
newArray[from] = newArray[to]; | ||
newArray[to] = item; | ||
|
||
return newArray; | ||
} | ||
|
||
type Items = UniqueIdentifier[] | { id: UniqueIdentifier }[]; | ||
|
||
function mutate< | ||
T extends Items | Record<UniqueIdentifier, Items>, | ||
U extends Draggable, | ||
V extends Droppable, | ||
W extends DragDropManager<U, V>, | ||
>( | ||
items: T, | ||
event: Parameters< | ||
DragDropEvents<U, V, W>["dragover"] | DragDropEvents<U, V, W>["dragend"] | ||
>[0], | ||
mutation: typeof arrayMove | typeof arraySwap | ||
): T { | ||
const { source, target, canceled } = event.operation; | ||
|
||
if (!source || !target || canceled || source.id === target.id) { | ||
if ("preventDefault" in event) event.preventDefault(); | ||
return items; | ||
} | ||
|
||
const findIndex = (item: Items[0], id: UniqueIdentifier) => | ||
item === id || (typeof item === "object" && "id" in item && item.id === id); | ||
|
||
if (Array.isArray(items)) { | ||
const sourceIndex = items.findIndex((item) => findIndex(item, source.id)); | ||
const targetIndex = items.findIndex((item) => findIndex(item, target.id)); | ||
|
||
if (sourceIndex === -1 || targetIndex === -1) { | ||
return items; | ||
} | ||
|
||
// Reconcile optimistic updates | ||
if (!canceled && "index" in source && typeof source.index === "number") { | ||
const projectedSourceIndex = source.index; | ||
|
||
if (projectedSourceIndex !== sourceIndex) { | ||
return mutation(items, sourceIndex, projectedSourceIndex); | ||
} | ||
} | ||
|
||
return mutation(items, sourceIndex, targetIndex); | ||
} | ||
|
||
const entries = Object.entries(items); | ||
|
||
let sourceIndex = -1; | ||
let sourceParent: UniqueIdentifier | undefined; | ||
let targetIndex = -1; | ||
let targetParent: UniqueIdentifier | undefined; | ||
|
||
for (const [id, children] of entries) { | ||
if (sourceIndex === -1) { | ||
sourceIndex = children.findIndex((item) => findIndex(item, source.id)); | ||
|
||
if (sourceIndex !== -1) { | ||
sourceParent = id; | ||
} | ||
} | ||
|
||
if (targetIndex === -1) { | ||
targetIndex = children.findIndex((item) => findIndex(item, target.id)); | ||
|
||
if (targetIndex !== -1) { | ||
targetParent = id; | ||
} | ||
} | ||
|
||
if (sourceIndex !== -1 && targetIndex !== -1) { | ||
break; | ||
} | ||
} | ||
|
||
if (!source.manager) return items; | ||
|
||
const { dragOperation } = source.manager; | ||
const position = | ||
dragOperation.shape?.current.center ?? dragOperation.position.current; | ||
|
||
if (targetParent == null) { | ||
if (target.id in items) { | ||
const insertionIndex = | ||
target.shape && position.y > target.shape.center.y | ||
? items[target.id].length | ||
: 0; | ||
|
||
// The target does not have any matching children, but appears to be a valid target | ||
targetParent = target.id; | ||
targetIndex = insertionIndex; | ||
} | ||
} | ||
|
||
if ( | ||
sourceParent == null || | ||
targetParent == null || | ||
(sourceParent === targetParent && sourceIndex === targetIndex) | ||
) { | ||
if ("preventDefault" in event) event.preventDefault(); | ||
|
||
return items; | ||
} | ||
|
||
if (sourceParent === targetParent) { | ||
return { | ||
...items, | ||
[sourceParent]: mutation(items[sourceParent], sourceIndex, targetIndex), | ||
}; | ||
} | ||
|
||
const isBelowTarget = target.shape && position.y > target.shape.center.y; | ||
const modifier = isBelowTarget ? 1 : 0; | ||
const sourceItem = items[sourceParent][sourceIndex]; | ||
|
||
return { | ||
...items, | ||
[sourceParent]: [ | ||
...items[sourceParent].slice(0, sourceIndex), | ||
...items[sourceParent].slice(sourceIndex + 1), | ||
], | ||
[targetParent]: [ | ||
...items[targetParent].slice(0, targetIndex + modifier), | ||
sourceItem, | ||
...items[targetParent].slice(targetIndex + modifier), | ||
], | ||
}; | ||
} | ||
|
||
export function move< | ||
T extends Items | Record<UniqueIdentifier, Items>, | ||
U extends Draggable, | ||
V extends Droppable, | ||
W extends DragDropManager<U, V>, | ||
>( | ||
items: T, | ||
event: Parameters< | ||
DragDropEvents<U, V, W>["dragover"] | DragDropEvents<U, V, W>["dragend"] | ||
>[0] | ||
) { | ||
return mutate(items, event, arrayMove); | ||
} | ||
|
||
export function swap< | ||
T extends Items | Record<UniqueIdentifier, Items>, | ||
U extends Draggable, | ||
V extends Droppable, | ||
W extends DragDropManager<U, V>, | ||
>( | ||
items: T, | ||
event: Parameters< | ||
DragDropEvents<U, V, W>["dragover"] | DragDropEvents<U, V, W>["dragend"] | ||
>[0] | ||
) { | ||
return mutate(items, event, arraySwap); | ||
} |
Oops, something went wrong.