@dnd-kit/sortable
Advanced tools
Comparing version 5.1.0 to 6.0.0-next-20220101438
130
CHANGELOG.md
# @dnd-kit/sortable | ||
## 6.0.0-next-20220101438 | ||
### Major Changes | ||
- [#518](https://github.com/clauderic/dnd-kit/pull/518) [`6310227`](https://github.com/clauderic/dnd-kit/commit/63102272d0d63dae349e2e9f638277e16a7d5970) Thanks [@clauderic](https://github.com/clauderic)! - Major internal refactor of measuring and collision detection. | ||
### Summary of changes | ||
Previously, all collision detection algorithms were relative to the top and left points of the document. While this approach worked in most situations, it broke down in a number of different use-cases, such as fixed position droppable containers and trying to drag between containers that had different scroll positions. | ||
This new approach changes the frame of comparison to be relative to the viewport. This is a major breaking change, and will need to be released under a new major version bump. | ||
### Breaking changes: | ||
- By default, `@dnd-kit` now ignores only the transforms applied to the draggable / droppable node itself, but considers all the transforms applied to its ancestors. This should provide the right balance of flexibility for most consumers. | ||
- Transforms applied to the droppable and draggable nodes are ignored by default, because the recommended approach for moving items on the screen is to use the transform property, which can interfere with the calculation of collisions. | ||
- Consumers can choose an alternate approach that does consider transforms for specific use-cases if needed by configuring the measuring prop of <DndContext>. Refer to the <Switch> example. | ||
- Reduced the number of concepts related to measuring from `ViewRect`, `LayoutRect` to just a single concept of `ClientRect`. | ||
- The `ClientRect` interface no longer holds the `offsetTop` and `offsetLeft` properties. For most use-cases, you can replace `offsetTop` with `top` and `offsetLeft` with `left`. | ||
- Replaced the following exports from the `@dnd-kit/core` package with `getClientRect`: | ||
- `getBoundingClientRect` | ||
- `getViewRect` | ||
- `getLayoutRect` | ||
- `getViewportLayoutRect` | ||
- Removed `translatedRect` from the `SensorContext` interface. Replace usage with `collisionRect`. | ||
- Removed `activeNodeClientRect` on the `DndContext` interface. Replace with `activeNodeRect`. | ||
- [#569](https://github.com/clauderic/dnd-kit/pull/569) [`e7ac3d4`](https://github.com/clauderic/dnd-kit/commit/e7ac3d45699dcc7b47191a67044a516929ac439c) Thanks [@clauderic](https://github.com/clauderic)! - Separated context into public and internal context providers. Certain properties that used to be available on the public `DndContextDescriptor` interface have been moved to the internal context provider and are no longer exposed to consumers: | ||
```ts | ||
interface DndContextDescriptor { | ||
- dispatch: React.Dispatch<Actions>; | ||
- activators: SyntheticListeners; | ||
- ariaDescribedById: { | ||
- draggable: UniqueIdentifier; | ||
- }; | ||
} | ||
``` | ||
Having two distinct context providers will allow to keep certain internals such as `dispatch` hidden from consumers. | ||
It also serves as an optimization until context selectors are implemented in React, properties that change often, such as the droppable containers and droppable rects, the transform value and array of collisions should be stored on a different context provider to limit un-necessary re-renders in `useDraggable`, `useDroppable` and `useSortable`. | ||
The `<InternalContext.Provider>` is also reset to its default values within `<DragOverlay>`. This paves the way towards being able to seamlessly use components that use hooks such as `useDraggable` and `useDroppable` as children of `<DragOverlay>` without causing interference or namespace collisions. | ||
Consumers can still make calls to `useDndContext()` to get the `active` or `over` properties if they wish to re-render the component rendered within `DragOverlay` in response to user interaction, since those use the `PublicContext` | ||
### Minor Changes | ||
- [#558](https://github.com/clauderic/dnd-kit/pull/558) [`f3ad20d`](https://github.com/clauderic/dnd-kit/commit/f3ad20d5b2c2f2ca7b82c193c9af5eef38c5ce11) Thanks [@clauderic](https://github.com/clauderic)! - Refactor of the `CollisionDetection` interface to return an array of `Collision`s: | ||
```diff | ||
+export interface Collision { | ||
+ id: UniqueIdentifier; | ||
+ data?: Record<string, any>; | ||
+} | ||
export type CollisionDetection = (args: { | ||
active: Active; | ||
collisionRect: ClientRect; | ||
droppableContainers: DroppableContainer[]; | ||
pointerCoordinates: Coordinates | null; | ||
-}) => UniqueIdentifier; | ||
+}) => Collision[]; | ||
``` | ||
This is a breaking change that requires all collision detection strategies to be updated to return an array of `Collision` rather than a single `UniqueIdentifier` | ||
The `over` property remains a single `UniqueIdentifier`, and is set to the first item in returned in the collisions array. | ||
Consumers can also access the `collisions` property which can be used to implement use-cases such as combining droppables in user-land. | ||
The `onDragMove`, `onDragOver` and `onDragEnd` callbacks are also updated to receive the collisions array property. | ||
Built-in collision detections such as rectIntersection, closestCenter, closestCorners and pointerWithin adhere to the CollisionDescriptor interface, which extends the Collision interface: | ||
```ts | ||
export interface CollisionDescriptor extends Collision { | ||
data: { | ||
droppableContainer: DroppableContainer; | ||
value: number; | ||
[key: string]: any; | ||
}; | ||
} | ||
``` | ||
Consumers can also access the array of collisions in components wrapped by `<DndContext>` via the `useDndContext()` hook: | ||
```ts | ||
import {useDndContext} from '@dnd-kit/core'; | ||
function MyComponent() { | ||
const {collisions} = useDndContext(); | ||
} | ||
``` | ||
- [#561](https://github.com/clauderic/dnd-kit/pull/561) [`02edd26`](https://github.com/clauderic/dnd-kit/commit/02edd2691b24bb49f2e7c9f9a3f282031bf658b7) Thanks [@clauderic](https://github.com/clauderic)! - Droppable containers now observe the node they are attached to via `setNodeRef` using `ResizeObserver` while dragging. | ||
This behaviour can be configured using the newly introduced `resizeObserverConfig` property. | ||
```ts | ||
interface ResizeObserverConfig { | ||
/** Whether the ResizeObserver should be disabled entirely */ | ||
disabled?: boolean; | ||
/** Resize events may affect the layout and position of other droppable containers. | ||
* Specify an array of `UniqueIdentifier` of droppable containers that should also be re-measured | ||
* when this droppable container resizes. Specifying an empty array re-measures all droppable containers. | ||
*/ | ||
updateMeasurementsFor?: UniqueIdentifier[]; | ||
/** Represents the debounce timeout between when resize events are observed and when elements are re-measured */ | ||
timeout?: number; | ||
} | ||
``` | ||
By default, only the current droppable is scheduled to be re-measured when a resize event is observed. However, this may not be suitable for all use-cases. When an element resizes, it can affect the layout and position of other elements, such that it may be necessary to re-measure other droppable nodes in response to that single resize event. The `recomputeIds` property can be used to specify which droppable `id`s should be re-measured in response to resize events being observed. | ||
For example, the `useSortable` preset re-computes the measurements of all sortable elements after the element that resizes, so long as they are within the same `SortableContext` as the element that resizes, since it's highly likely that their layout will also shift. | ||
Specifying an empty array for `recomputeIds` forces all droppable containers to be re-measured. | ||
For consumers that were relyings on the internals of `DndContext` using `useDndContext()`, the `willRecomputeLayouts` property has been renamed to `measuringScheduled`, and the `recomputeLayouts` method has been renamed to `measureDroppableContainers`, and now optionally accepts an array of droppable `UniqueIdentifier` that should be scheduled to be re-measured. | ||
### Patch Changes | ||
- [#566](https://github.com/clauderic/dnd-kit/pull/566) [`d315df0`](https://github.com/clauderic/dnd-kit/commit/d315df07022178460a52d6021a41227878b876b8) Thanks [@clauderic](https://github.com/clauderic)! - Fixed a bug where sortable item position was not updated when quickly dragging different sortable items. | ||
- Updated dependencies [[`f3ad20d`](https://github.com/clauderic/dnd-kit/commit/f3ad20d5b2c2f2ca7b82c193c9af5eef38c5ce11), [`02edd26`](https://github.com/clauderic/dnd-kit/commit/02edd2691b24bb49f2e7c9f9a3f282031bf658b7), [`c6c67cb`](https://github.com/clauderic/dnd-kit/commit/c6c67cb9cbc6e61027f7bb084fd2232160037d5e), [`6310227`](https://github.com/clauderic/dnd-kit/commit/63102272d0d63dae349e2e9f638277e16a7d5970), [`e7ac3d4`](https://github.com/clauderic/dnd-kit/commit/e7ac3d45699dcc7b47191a67044a516929ac439c), [`528c67e`](https://github.com/clauderic/dnd-kit/commit/528c67e4c617dfc0ce5221496aa8b222ffc82ddb), [`02edd26`](https://github.com/clauderic/dnd-kit/commit/02edd2691b24bb49f2e7c9f9a3f282031bf658b7)]: | ||
- @dnd-kit/core@5.0.0-next-20220101438 | ||
- @dnd-kit/utilities@3.1.0-next-20220101438 | ||
## 5.1.0 | ||
@@ -4,0 +134,0 @@ |
@@ -1,3 +0,3 @@ | ||
import React, { MutableRefObject } from 'react'; | ||
import { LayoutRect, UniqueIdentifier } from '@dnd-kit/core'; | ||
import React from 'react'; | ||
import { ClientRect, UniqueIdentifier } from '@dnd-kit/core'; | ||
import type { SortingStrategy } from '../types'; | ||
@@ -19,5 +19,4 @@ export interface Props { | ||
useDragOverlay: boolean; | ||
sortedRects: LayoutRect[]; | ||
sortedRects: ClientRect[]; | ||
strategy: SortingStrategy; | ||
wasDragging: MutableRefObject<boolean>; | ||
} | ||
@@ -24,0 +23,0 @@ export declare const Context: React.Context<ContextDescriptor>; |
/// <reference types="react" /> | ||
import { UseDraggableArguments } from '@dnd-kit/core'; | ||
import { UseDraggableArguments, UseDroppableArguments } from '@dnd-kit/core'; | ||
import type { SortingStrategy } from '../types'; | ||
import type { AnimateLayoutChanges, NewIndexGetter, SortableTransition } from './types'; | ||
export interface Arguments extends UseDraggableArguments { | ||
export interface Arguments extends UseDraggableArguments, Pick<UseDroppableArguments, 'resizeObserverConfig'> { | ||
animateLayoutChanges?: AnimateLayoutChanges; | ||
@@ -11,4 +11,5 @@ getNewIndex?: NewIndexGetter; | ||
} | ||
export declare function useSortable({ animateLayoutChanges, attributes: userDefinedAttributes, disabled, data: customData, getNewIndex, id, strategy: localStrategy, transition, }: Arguments): { | ||
export declare function useSortable({ animateLayoutChanges, attributes: userDefinedAttributes, disabled, data: customData, getNewIndex, id, strategy: localStrategy, resizeObserverConfig, transition, }: Arguments): { | ||
active: import("@dnd-kit/core").Active | null; | ||
activeIndex: number; | ||
attributes: { | ||
@@ -21,8 +22,10 @@ role: string; | ||
}; | ||
activatorEvent: Event | null; | ||
rect: import("react").MutableRefObject<import("@dnd-kit/core").LayoutRect | null>; | ||
rect: import("react").MutableRefObject<import("@dnd-kit/core").ClientRect | null>; | ||
index: number; | ||
newIndex: number; | ||
items: string[]; | ||
isOver: boolean; | ||
isSorting: boolean; | ||
isDragging: boolean; | ||
listeners: import("@dnd-kit/core").DraggableSyntheticListeners; | ||
listeners: import("@dnd-kit/core/dist/hooks/utilities").SyntheticListenerMap | undefined; | ||
node: import("react").MutableRefObject<HTMLElement | null>; | ||
@@ -29,0 +32,0 @@ overIndex: number; |
/// <reference types="react" /> | ||
import { LayoutRect } from '@dnd-kit/core'; | ||
import { ClientRect } from '@dnd-kit/core'; | ||
import { Transform } from '@dnd-kit/utilities'; | ||
interface Arguments { | ||
rect: React.MutableRefObject<LayoutRect | null>; | ||
rect: React.MutableRefObject<ClientRect | null>; | ||
disabled: boolean; | ||
@@ -7,0 +7,0 @@ index: number; |
@@ -31,8 +31,8 @@ 'use strict'; | ||
function getSortedRects(items, layoutRects) { | ||
function getSortedRects(items, rects) { | ||
return items.reduce((accumulator, id, index) => { | ||
const layoutRect = layoutRects.get(id); | ||
const rect = rects.get(id); | ||
if (layoutRect) { | ||
accumulator[index] = layoutRect; | ||
if (rect) { | ||
accumulator[index] = rect; | ||
} | ||
@@ -54,3 +54,3 @@ | ||
const horizontalListSortingStrategy = ({ | ||
layoutRects, | ||
rects, | ||
activeNodeRect: fallbackActiveRect, | ||
@@ -61,5 +61,5 @@ activeIndex, | ||
}) => { | ||
var _layoutRects$activeIn; | ||
var _rects$activeIndex; | ||
const activeNodeRect = (_layoutRects$activeIn = layoutRects[activeIndex]) != null ? _layoutRects$activeIn : fallbackActiveRect; | ||
const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect; | ||
@@ -70,6 +70,6 @@ if (!activeNodeRect) { | ||
const itemGap = getItemGap(layoutRects, index, activeIndex); | ||
const itemGap = getItemGap(rects, index, activeIndex); | ||
if (index === activeIndex) { | ||
const newIndexRect = layoutRects[overIndex]; | ||
const newIndexRect = rects[overIndex]; | ||
@@ -81,3 +81,3 @@ if (!newIndexRect) { | ||
return { | ||
x: activeIndex < overIndex ? newIndexRect.offsetLeft + newIndexRect.width - (activeNodeRect.offsetLeft + activeNodeRect.width) : newIndexRect.offsetLeft - activeNodeRect.offsetLeft, | ||
x: activeIndex < overIndex ? newIndexRect.left + newIndexRect.width - (activeNodeRect.left + activeNodeRect.width) : newIndexRect.left - activeNodeRect.left, | ||
y: 0, | ||
@@ -111,6 +111,6 @@ ...defaultScale | ||
function getItemGap(layoutRects, index, activeIndex) { | ||
const currentRect = layoutRects[index]; | ||
const previousRect = layoutRects[index - 1]; | ||
const nextRect = layoutRects[index + 1]; | ||
function getItemGap(rects, index, activeIndex) { | ||
const currentRect = rects[index]; | ||
const previousRect = rects[index - 1]; | ||
const nextRect = rects[index + 1]; | ||
@@ -122,10 +122,10 @@ if (!currentRect || !previousRect && !nextRect) { | ||
if (activeIndex < index) { | ||
return previousRect ? currentRect.offsetLeft - (previousRect.offsetLeft + previousRect.width) : nextRect.offsetLeft - (currentRect.offsetLeft + currentRect.width); | ||
return previousRect ? currentRect.left - (previousRect.left + previousRect.width) : nextRect.left - (currentRect.left + currentRect.width); | ||
} | ||
return nextRect ? nextRect.offsetLeft - (currentRect.offsetLeft + currentRect.width) : currentRect.offsetLeft - (previousRect.offsetLeft + previousRect.width); | ||
return nextRect ? nextRect.left - (currentRect.left + currentRect.width) : currentRect.left - (previousRect.left + previousRect.width); | ||
} | ||
const rectSortingStrategy = ({ | ||
layoutRects, | ||
rects, | ||
activeIndex, | ||
@@ -135,4 +135,4 @@ overIndex, | ||
}) => { | ||
const newRects = arrayMove(layoutRects, overIndex, activeIndex); | ||
const oldRect = layoutRects[index]; | ||
const newRects = arrayMove(rects, overIndex, activeIndex); | ||
const oldRect = rects[index]; | ||
const newRect = newRects[index]; | ||
@@ -145,4 +145,4 @@ | ||
return { | ||
x: newRect.offsetLeft - oldRect.offsetLeft, | ||
y: newRect.offsetTop - oldRect.offsetTop, | ||
x: newRect.left - oldRect.left, | ||
y: newRect.top - oldRect.top, | ||
scaleX: newRect.width / oldRect.width, | ||
@@ -156,3 +156,3 @@ scaleY: newRect.height / oldRect.height | ||
index, | ||
layoutRects, | ||
rects, | ||
overIndex | ||
@@ -164,9 +164,9 @@ }) => { | ||
if (index === activeIndex) { | ||
oldRect = layoutRects[index]; | ||
newRect = layoutRects[overIndex]; | ||
oldRect = rects[index]; | ||
newRect = rects[overIndex]; | ||
} | ||
if (index === overIndex) { | ||
oldRect = layoutRects[index]; | ||
newRect = layoutRects[activeIndex]; | ||
oldRect = rects[index]; | ||
newRect = rects[activeIndex]; | ||
} | ||
@@ -179,4 +179,4 @@ | ||
return { | ||
x: newRect.offsetLeft - oldRect.offsetLeft, | ||
y: newRect.offsetTop - oldRect.offsetTop, | ||
x: newRect.left - oldRect.left, | ||
y: newRect.top - oldRect.top, | ||
scaleX: newRect.width / oldRect.width, | ||
@@ -196,8 +196,8 @@ scaleY: newRect.height / oldRect.height | ||
index, | ||
layoutRects, | ||
rects, | ||
overIndex | ||
}) => { | ||
var _layoutRects$activeIn; | ||
var _rects$activeIndex; | ||
const activeNodeRect = (_layoutRects$activeIn = layoutRects[activeIndex]) != null ? _layoutRects$activeIn : fallbackActiveRect; | ||
const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect; | ||
@@ -209,3 +209,3 @@ if (!activeNodeRect) { | ||
if (index === activeIndex) { | ||
const overIndexRect = layoutRects[overIndex]; | ||
const overIndexRect = rects[overIndex]; | ||
@@ -218,3 +218,3 @@ if (!overIndexRect) { | ||
x: 0, | ||
y: activeIndex < overIndex ? overIndexRect.offsetTop + overIndexRect.height - (activeNodeRect.offsetTop + activeNodeRect.height) : overIndexRect.offsetTop - activeNodeRect.offsetTop, | ||
y: activeIndex < overIndex ? overIndexRect.top + overIndexRect.height - (activeNodeRect.top + activeNodeRect.height) : overIndexRect.top - activeNodeRect.top, | ||
...defaultScale$1 | ||
@@ -224,3 +224,3 @@ }; | ||
const itemGap = getItemGap$1(layoutRects, index, activeIndex); | ||
const itemGap = getItemGap$1(rects, index, activeIndex); | ||
@@ -250,6 +250,6 @@ if (index > activeIndex && index <= overIndex) { | ||
function getItemGap$1(layoutRects, index, activeIndex) { | ||
const currentRect = layoutRects[index]; | ||
const previousRect = layoutRects[index - 1]; | ||
const nextRect = layoutRects[index + 1]; | ||
function getItemGap$1(clientRects, index, activeIndex) { | ||
const currentRect = clientRects[index]; | ||
const previousRect = clientRects[index - 1]; | ||
const nextRect = clientRects[index + 1]; | ||
@@ -261,6 +261,6 @@ if (!currentRect) { | ||
if (activeIndex < index) { | ||
return previousRect ? currentRect.offsetTop - (previousRect.offsetTop + previousRect.height) : nextRect ? nextRect.offsetTop - (currentRect.offsetTop + currentRect.height) : 0; | ||
return previousRect ? currentRect.top - (previousRect.top + previousRect.height) : nextRect ? nextRect.top - (currentRect.top + currentRect.height) : 0; | ||
} | ||
return nextRect ? nextRect.offsetTop - (currentRect.offsetTop + currentRect.height) : previousRect ? currentRect.offsetTop - (previousRect.offsetTop + previousRect.height) : 0; | ||
return nextRect ? nextRect.top - (currentRect.top + currentRect.height) : previousRect ? currentRect.top - (previousRect.top + previousRect.height) : 0; | ||
} | ||
@@ -277,6 +277,3 @@ | ||
sortedRects: [], | ||
strategy: rectSortingStrategy, | ||
wasDragging: { | ||
current: false | ||
} | ||
strategy: rectSortingStrategy | ||
}); | ||
@@ -294,4 +291,4 @@ function SortableContext({ | ||
over, | ||
recomputeLayouts, | ||
willRecomputeLayouts | ||
measureDroppableContainers, | ||
measuringScheduled | ||
} = core.useDndContext(); | ||
@@ -302,5 +299,3 @@ const containerId = utilities.useUniqueId(ID_PREFIX, id); | ||
const isDragging = active != null; | ||
const wasDragging = React.useRef(false); | ||
const activeIndex = active ? items.indexOf(active.id) : -1; | ||
const isSorting = activeIndex !== -1; | ||
const overIndex = over ? items.indexOf(over.id) : -1; | ||
@@ -312,16 +307,9 @@ const previousItemsRef = React.useRef(items); | ||
utilities.useIsomorphicLayoutEffect(() => { | ||
if (itemsHaveChanged && isSorting && !willRecomputeLayouts) { | ||
// To-do: Add partial recompution of only subset of rects | ||
recomputeLayouts(); | ||
if (itemsHaveChanged && isDragging && !measuringScheduled) { | ||
measureDroppableContainers(items); | ||
} | ||
}, [itemsHaveChanged, isSorting, recomputeLayouts, willRecomputeLayouts]); | ||
}, [itemsHaveChanged, items, isDragging, measureDroppableContainers, measuringScheduled]); | ||
React.useEffect(() => { | ||
previousItemsRef.current = items; | ||
}, [items]); | ||
React.useEffect(() => { | ||
const timeoutId = setTimeout(() => { | ||
wasDragging.current = isDragging; | ||
}, 100); | ||
return () => clearTimeout(timeoutId); | ||
}, [isDragging]); | ||
const contextValue = React.useMemo(() => ({ | ||
@@ -335,5 +323,4 @@ activeIndex, | ||
sortedRects, | ||
strategy, | ||
wasDragging | ||
}), [activeIndex, containerId, disableTransforms, items, overIndex, sortedRects, useDragOverlay, strategy, wasDragging]); | ||
strategy | ||
}), [activeIndex, containerId, disableTransforms, items, overIndex, sortedRects, useDragOverlay, strategy]); | ||
return React__default.createElement(Context.Provider, { | ||
@@ -411,6 +398,8 @@ value: contextValue | ||
if (initial) { | ||
const current = core.getBoundingClientRect(node.current); | ||
const current = core.getClientRect(node.current, { | ||
ignoreTransform: true | ||
}); | ||
const delta = { | ||
x: initial.offsetLeft - current.offsetLeft, | ||
y: initial.offsetTop - current.offsetTop, | ||
x: initial.left - current.left, | ||
y: initial.top - current.top, | ||
scaleX: initial.width / current.width, | ||
@@ -448,2 +437,3 @@ scaleY: initial.height / current.height | ||
strategy: localStrategy, | ||
resizeObserverConfig, | ||
transition = defaultTransition | ||
@@ -459,4 +449,3 @@ }) { | ||
useDragOverlay, | ||
strategy: globalStrategy, | ||
wasDragging | ||
strategy: globalStrategy | ||
} = React.useContext(Context); | ||
@@ -472,9 +461,15 @@ const index = items.indexOf(id); | ||
}), [containerId, customData, index, items]); | ||
const itemsAfterCurrentSortable = React.useMemo(() => items.slice(items.indexOf(id)), [items, id]); | ||
const { | ||
rect, | ||
node, | ||
isOver, | ||
setNodeRef: setDroppableNodeRef | ||
} = core.useDroppable({ | ||
id, | ||
data | ||
data, | ||
resizeObserverConfig: { | ||
updateMeasurementsFor: itemsAfterCurrentSortable, | ||
...resizeObserverConfig | ||
} | ||
}); | ||
@@ -484,3 +479,2 @@ const { | ||
activeNodeRect, | ||
activatorEvent, | ||
attributes, | ||
@@ -502,3 +496,3 @@ setNodeRef: setDraggableNodeRef, | ||
const isSorting = Boolean(active); | ||
const displaceItem = isSorting && wasDragging.current && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex); | ||
const displaceItem = isSorting && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex); | ||
const shouldDisplaceDragSource = !useDragOverlay && isDragging; | ||
@@ -508,3 +502,3 @@ const dragSourceDisplacement = shouldDisplaceDragSource && displaceItem ? transform : null; | ||
const finalTransform = displaceItem ? dragSourceDisplacement != null ? dragSourceDisplacement : strategy({ | ||
layoutRects: sortedRects, | ||
rects: sortedRects, | ||
activeNodeRect, | ||
@@ -521,6 +515,10 @@ activeIndex, | ||
}) : index; | ||
const prevItems = React.useRef(items); | ||
const itemsHaveChanged = items !== prevItems.current; | ||
const prevNewIndex = React.useRef(newIndex); | ||
const previousContainerId = React.useRef(containerId); | ||
const activeId = active == null ? void 0 : active.id; | ||
const previous = React.useRef({ | ||
activeId, | ||
items, | ||
newIndex, | ||
containerId | ||
}); | ||
const itemsHaveChanged = items !== previous.current.items; | ||
const shouldAnimateLayoutChanges = animateLayoutChanges({ | ||
@@ -534,7 +532,7 @@ active, | ||
items, | ||
newIndex: prevNewIndex.current, | ||
previousItems: prevItems.current, | ||
previousContainerId: previousContainerId.current, | ||
newIndex: previous.current.newIndex, | ||
previousItems: previous.current.items, | ||
previousContainerId: previous.current.containerId, | ||
transition, | ||
wasDragging: wasDragging.current | ||
wasDragging: previous.current.activeId != null | ||
}); | ||
@@ -548,20 +546,27 @@ const derivedTransform = useDerivedTransform({ | ||
React.useEffect(() => { | ||
if (isSorting && prevNewIndex.current !== newIndex) { | ||
prevNewIndex.current = newIndex; | ||
if (isSorting && previous.current.newIndex !== newIndex) { | ||
previous.current.newIndex = newIndex; | ||
} | ||
if (containerId !== previousContainerId.current) { | ||
previousContainerId.current = containerId; | ||
if (containerId !== previous.current.containerId) { | ||
previous.current.containerId = containerId; | ||
} | ||
if (items !== prevItems.current) { | ||
prevItems.current = items; | ||
if (items !== previous.current.items) { | ||
previous.current.items = items; | ||
} | ||
}, [isSorting, newIndex, containerId, items]); | ||
if (activeId !== previous.current.activeId) { | ||
previous.current.activeId = activeId; | ||
} | ||
}, [activeId, isSorting, newIndex, containerId, items]); | ||
return { | ||
active, | ||
activeIndex, | ||
attributes, | ||
activatorEvent, | ||
rect, | ||
index, | ||
newIndex, | ||
items, | ||
isOver, | ||
isSorting, | ||
@@ -583,3 +588,3 @@ isDragging, | ||
derivedTransform || // Or to prevent items jumping to back to their "new" position when items change | ||
itemsHaveChanged && prevNewIndex.current === index) { | ||
itemsHaveChanged && previous.current.newIndex === index) { | ||
return disabledTransition; | ||
@@ -607,3 +612,3 @@ } | ||
droppableContainers, | ||
translatedRect, | ||
collisionRect, | ||
scrollableAncestors | ||
@@ -615,3 +620,3 @@ } | ||
if (!active || !translatedRect) { | ||
if (!active || !collisionRect) { | ||
return; | ||
@@ -626,19 +631,12 @@ } | ||
const node = entry == null ? void 0 : entry.node.current; | ||
const rect = entry == null ? void 0 : entry.rect.current; | ||
if (!node) { | ||
if (!rect) { | ||
return; | ||
} | ||
const rect = core.getViewRect(node); | ||
const container = { ...entry, | ||
rect: { | ||
current: rect | ||
} | ||
}; | ||
switch (event.code) { | ||
case core.KeyboardCode.Down: | ||
if (translatedRect.top + translatedRect.height <= rect.top) { | ||
filteredContainers.push(container); | ||
if (collisionRect.top + collisionRect.height <= rect.top) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -649,4 +647,4 @@ | ||
case core.KeyboardCode.Up: | ||
if (translatedRect.top >= rect.top + rect.height) { | ||
filteredContainers.push(container); | ||
if (collisionRect.top >= rect.top + rect.height) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -657,4 +655,4 @@ | ||
case core.KeyboardCode.Left: | ||
if (translatedRect.left >= rect.left + rect.width) { | ||
filteredContainers.push(container); | ||
if (collisionRect.left >= rect.left + rect.width) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -665,4 +663,4 @@ | ||
case core.KeyboardCode.Right: | ||
if (translatedRect.left + translatedRect.width <= rect.left) { | ||
filteredContainers.push(container); | ||
if (collisionRect.left + collisionRect.width <= rect.left) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -673,17 +671,18 @@ | ||
}); | ||
const closestId = core.closestCorners({ | ||
const collisions = core.closestCorners({ | ||
active, | ||
collisionRect: translatedRect, | ||
droppableContainers: filteredContainers | ||
collisionRect: collisionRect, | ||
droppableContainers: filteredContainers, | ||
pointerCoordinates: null | ||
}); | ||
const closestId = core.getFirstCollision(collisions, 'id'); | ||
if (closestId) { | ||
var _droppableContainers$; | ||
if (closestId != null) { | ||
const newDroppable = droppableContainers.get(closestId); | ||
const newNode = newDroppable == null ? void 0 : newDroppable.node.current; | ||
const newRect = newDroppable == null ? void 0 : newDroppable.rect.current; | ||
const newNode = (_droppableContainers$ = droppableContainers.get(closestId)) == null ? void 0 : _droppableContainers$.node.current; | ||
if (newNode) { | ||
if (newNode && newRect) { | ||
const newScrollAncestors = core.getScrollableAncestors(newNode); | ||
const hasDifferentScrollAncestors = newScrollAncestors.some((element, index) => scrollableAncestors[index] !== element); | ||
const newRect = core.getViewRect(newNode); | ||
const offset = hasDifferentScrollAncestors ? { | ||
@@ -693,4 +692,4 @@ x: 0, | ||
} : { | ||
x: translatedRect.width - newRect.width, | ||
y: translatedRect.height - newRect.height | ||
x: collisionRect.width - newRect.width, | ||
y: collisionRect.height - newRect.height | ||
}; | ||
@@ -697,0 +696,0 @@ const newCoordinates = { |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("react"),r=(e=t)&&"object"==typeof e&&"default"in e?e.default:e,o=require("@dnd-kit/core"),n=require("@dnd-kit/utilities");function s(e,t,r){const o=e.slice();return o.splice(r<0?o.length+r:r,0,o.splice(t,1)[0]),o}function i(e){return null!==e&&e>=0}const a={scaleX:1,scaleY:1},c=({layoutRects:e,activeIndex:t,overIndex:r,index:o})=>{const n=s(e,r,t),i=e[o],a=n[o];return a&&i?{x:a.offsetLeft-i.offsetLeft,y:a.offsetTop-i.offsetTop,scaleX:a.width/i.width,scaleY:a.height/i.height}:null},f={scaleX:1,scaleY:1},d=r.createContext({activeIndex:-1,containerId:"Sortable",disableTransforms:!1,items:[],overIndex:-1,useDragOverlay:!1,sortedRects:[],strategy:c,wasDragging:{current:!1}}),u=({id:e,items:t,activeIndex:r,overIndex:o})=>s(t,r,o).indexOf(e),l=({containerId:e,isSorting:t,wasDragging:r,index:o,items:n,newIndex:s,previousItems:i,previousContainerId:a,transition:c})=>!(!c||!r||i!==n&&o===s||!t&&(s===o||e!==a)),g={duration:200,easing:"ease"},p=n.CSS.Transition.toString({property:"transform",duration:0,easing:"linear"}),x={roleDescription:"sortable"},h=[o.KeyboardCode.Down,o.KeyboardCode.Right,o.KeyboardCode.Up,o.KeyboardCode.Left];exports.SortableContext=function({children:e,id:s,items:i,strategy:a=c}){const{active:f,dragOverlay:u,droppableRects:l,over:g,recomputeLayouts:p,willRecomputeLayouts:x}=o.useDndContext(),h=n.useUniqueId("Sortable",s),v=Boolean(null!==u.rect),y=t.useMemo(()=>i.map(e=>"string"==typeof e?e:e.id),[i]),b=null!=f,I=t.useRef(!1),m=f?y.indexOf(f.id):-1,w=-1!==m,R=g?y.indexOf(g.id):-1,L=t.useRef(y),T=function(e,t){return e.reduce((e,r,o)=>{const n=t.get(r);return n&&(e[o]=n),e},Array(e.length))}(y,l),C=(S=L.current,!(y.join()===S.join()));var S;const D=-1!==R&&-1===m||C;n.useIsomorphicLayoutEffect(()=>{C&&w&&!x&&p()},[C,w,p,x]),t.useEffect(()=>{L.current=y},[y]),t.useEffect(()=>{const e=setTimeout(()=>{I.current=b},100);return()=>clearTimeout(e)},[b]);const E=t.useMemo(()=>({activeIndex:m,containerId:h,disableTransforms:D,items:y,overIndex:R,useDragOverlay:v,sortedRects:T,strategy:a,wasDragging:I}),[m,h,D,y,R,T,v,a,I]);return r.createElement(d.Provider,{value:E},e)},exports.arrayMove=s,exports.arraySwap=function(e,t,r){const o=e.slice();return o[t]=e[r],o[r]=e[t],o},exports.defaultAnimateLayoutChanges=l,exports.defaultNewIndexGetter=u,exports.horizontalListSortingStrategy=({layoutRects:e,activeNodeRect:t,activeIndex:r,overIndex:o,index:n})=>{var s;const i=null!=(s=e[r])?s:t;if(!i)return null;const c=function(e,t,r){const o=e[t],n=e[t-1],s=e[t+1];return o&&(n||s)?r<t?n?o.offsetLeft-(n.offsetLeft+n.width):s.offsetLeft-(o.offsetLeft+o.width):s?s.offsetLeft-(o.offsetLeft+o.width):o.offsetLeft-(n.offsetLeft+n.width):0}(e,n,r);if(n===r){const t=e[o];return t?{x:r<o?t.offsetLeft+t.width-(i.offsetLeft+i.width):t.offsetLeft-i.offsetLeft,y:0,...a}:null}return n>r&&n<=o?{x:-i.width-c,y:0,...a}:n<r&&n>=o?{x:i.width+c,y:0,...a}:{x:0,y:0,...a}},exports.rectSortingStrategy=c,exports.rectSwappingStrategy=({activeIndex:e,index:t,layoutRects:r,overIndex:o})=>{let n,s;return t===e&&(n=r[t],s=r[o]),t===o&&(n=r[t],s=r[e]),s&&n?{x:s.offsetLeft-n.offsetLeft,y:s.offsetTop-n.offsetTop,scaleX:s.width/n.width,scaleY:s.height/n.height}:null},exports.sortableKeyboardCoordinates=(e,{context:{active:t,droppableContainers:r,translatedRect:n,scrollableAncestors:s}})=>{if(h.includes(e.code)){if(e.preventDefault(),!t||!n)return;const a=[];r.getEnabled().forEach(t=>{if(!t||(null==t?void 0:t.disabled))return;const r=null==t?void 0:t.node.current;if(!r)return;const s=o.getViewRect(r),i={...t,rect:{current:s}};switch(e.code){case o.KeyboardCode.Down:n.top+n.height<=s.top&&a.push(i);break;case o.KeyboardCode.Up:n.top>=s.top+s.height&&a.push(i);break;case o.KeyboardCode.Left:n.left>=s.left+s.width&&a.push(i);break;case o.KeyboardCode.Right:n.left+n.width<=s.left&&a.push(i)}});const c=o.closestCorners({active:t,collisionRect:n,droppableContainers:a});if(c){var i;const e=null==(i=r.get(c))?void 0:i.node.current;if(e){const t=o.getScrollableAncestors(e).some((e,t)=>s[t]!==e),r=o.getViewRect(e),i=t?{x:0,y:0}:{x:n.width-r.width,y:n.height-r.height};return{x:r.left-i.x,y:r.top-i.y}}}}},exports.useSortable=function({animateLayoutChanges:e=l,attributes:r,disabled:s,data:a,getNewIndex:c=u,id:f,strategy:h,transition:v=g}){const{items:y,containerId:b,activeIndex:I,disableTransforms:m,sortedRects:w,overIndex:R,useDragOverlay:L,strategy:T,wasDragging:C}=t.useContext(d),S=y.indexOf(f),D=t.useMemo(()=>({sortable:{containerId:b,index:S,items:y},...a}),[b,a,S,y]),{rect:E,node:N,setNodeRef:K}=o.useDroppable({id:f,data:D}),{active:O,activeNodeRect:k,activatorEvent:q,attributes:A,setNodeRef:M,listeners:X,isDragging:Y,over:j,transform:B}=o.useDraggable({id:f,data:D,attributes:{...x,...r},disabled:s}),U=n.useCombinedRefs(K,M),P=Boolean(O),V=P&&C.current&&!m&&i(I)&&i(R),_=!L&&Y,z=_&&V?B:null,F=V?null!=z?z:(null!=h?h:T)({layoutRects:w,activeNodeRect:k,activeIndex:I,overIndex:R,index:S}):null,G=i(I)&&i(R)?c({id:f,items:y,activeIndex:I,overIndex:R}):S,H=t.useRef(y),J=y!==H.current,Q=t.useRef(G),W=t.useRef(b),Z=e({active:O,containerId:b,isDragging:Y,isSorting:P,id:f,index:S,items:y,newIndex:Q.current,previousItems:H.current,previousContainerId:W.current,transition:v,wasDragging:C.current}),$=function({disabled:e,index:r,node:s,rect:i}){const[a,c]=t.useState(null),f=t.useRef(r);return n.useIsomorphicLayoutEffect(()=>{if(!e&&r!==f.current&&s.current){const e=i.current;if(e){const t=o.getBoundingClientRect(s.current),r={x:e.offsetLeft-t.offsetLeft,y:e.offsetTop-t.offsetTop,scaleX:e.width/t.width,scaleY:e.height/t.height};(r.x||r.y)&&c(r)}}r!==f.current&&(f.current=r)},[e,r,s,i]),t.useEffect(()=>{a&&requestAnimationFrame(()=>{c(null)})},[a]),a}({disabled:!Z,index:S,node:N,rect:E});return t.useEffect(()=>{P&&Q.current!==G&&(Q.current=G),b!==W.current&&(W.current=b),y!==H.current&&(H.current=y)},[P,G,b,y]),{active:O,attributes:A,activatorEvent:q,rect:E,index:S,isSorting:P,isDragging:Y,listeners:X,node:N,overIndex:R,over:j,setNodeRef:U,setDroppableNodeRef:K,setDraggableNodeRef:M,transform:null!=$?$:F,transition:$||J&&Q.current===S?p:!_&&v&&(P||Z)?n.CSS.Transition.toString({...v,property:"transform"}):void 0}},exports.verticalListSortingStrategy=({activeIndex:e,activeNodeRect:t,index:r,layoutRects:o,overIndex:n})=>{var s;const i=null!=(s=o[e])?s:t;if(!i)return null;if(r===e){const t=o[n];return t?{x:0,y:e<n?t.offsetTop+t.height-(i.offsetTop+i.height):t.offsetTop-i.offsetTop,...f}:null}const a=function(e,t,r){const o=e[t],n=e[t-1],s=e[t+1];return o?r<t?n?o.offsetTop-(n.offsetTop+n.height):s?s.offsetTop-(o.offsetTop+o.height):0:s?s.offsetTop-(o.offsetTop+o.height):n?o.offsetTop-(n.offsetTop+n.height):0:0}(o,r,e);return r>e&&r<=n?{x:0,y:-i.height-a,...f}:r<e&&r>=n?{x:0,y:i.height+a,...f}:{x:0,y:0,...f}}; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("react"),r=(e=t)&&"object"==typeof e&&"default"in e?e.default:e,n=require("@dnd-kit/core"),i=require("@dnd-kit/utilities");function o(e,t,r){const n=e.slice();return n.splice(r<0?n.length+r:r,0,n.splice(t,1)[0]),n}function s(e){return null!==e&&e>=0}const a={scaleX:1,scaleY:1},d=({rects:e,activeIndex:t,overIndex:r,index:n})=>{const i=o(e,r,t),s=e[n],a=i[n];return a&&s?{x:a.left-s.left,y:a.top-s.top,scaleX:a.width/s.width,scaleY:a.height/s.height}:null},c={scaleX:1,scaleY:1},l=r.createContext({activeIndex:-1,containerId:"Sortable",disableTransforms:!1,items:[],overIndex:-1,useDragOverlay:!1,sortedRects:[],strategy:d}),u=({id:e,items:t,activeIndex:r,overIndex:n})=>o(t,r,n).indexOf(e),f=({containerId:e,isSorting:t,wasDragging:r,index:n,items:i,newIndex:o,previousItems:s,previousContainerId:a,transition:d})=>!(!d||!r||s!==i&&n===o||!t&&(o===n||e!==a)),x={duration:200,easing:"ease"},g=i.CSS.Transition.toString({property:"transform",duration:0,easing:"linear"}),p={roleDescription:"sortable"},h=[n.KeyboardCode.Down,n.KeyboardCode.Right,n.KeyboardCode.Up,n.KeyboardCode.Left];exports.SortableContext=function({children:e,id:o,items:s,strategy:a=d}){const{active:c,dragOverlay:u,droppableRects:f,over:x,measureDroppableContainers:g,measuringScheduled:p}=n.useDndContext(),h=i.useUniqueId("Sortable",o),v=Boolean(null!==u.rect),I=t.useMemo(()=>s.map(e=>"string"==typeof e?e:e.id),[s]),y=null!=c,b=c?I.indexOf(c.id):-1,m=x?I.indexOf(x.id):-1,w=t.useRef(I),C=function(e,t){return e.reduce((e,r,n)=>{const i=t.get(r);return i&&(e[n]=i),e},Array(e.length))}(I,f),S=(R=w.current,!(I.join()===R.join()));var R;const D=-1!==m&&-1===b||S;i.useIsomorphicLayoutEffect(()=>{S&&y&&!p&&g(I)},[S,I,y,g,p]),t.useEffect(()=>{w.current=I},[I]);const O=t.useMemo(()=>({activeIndex:b,containerId:h,disableTransforms:D,items:I,overIndex:m,useDragOverlay:v,sortedRects:C,strategy:a}),[b,h,D,I,m,C,v,a]);return r.createElement(l.Provider,{value:O},e)},exports.arrayMove=o,exports.arraySwap=function(e,t,r){const n=e.slice();return n[t]=e[r],n[r]=e[t],n},exports.defaultAnimateLayoutChanges=f,exports.defaultNewIndexGetter=u,exports.horizontalListSortingStrategy=({rects:e,activeNodeRect:t,activeIndex:r,overIndex:n,index:i})=>{var o;const s=null!=(o=e[r])?o:t;if(!s)return null;const d=function(e,t,r){const n=e[t],i=e[t-1],o=e[t+1];return n&&(i||o)?r<t?i?n.left-(i.left+i.width):o.left-(n.left+n.width):o?o.left-(n.left+n.width):n.left-(i.left+i.width):0}(e,i,r);if(i===r){const t=e[n];return t?{x:r<n?t.left+t.width-(s.left+s.width):t.left-s.left,y:0,...a}:null}return i>r&&i<=n?{x:-s.width-d,y:0,...a}:i<r&&i>=n?{x:s.width+d,y:0,...a}:{x:0,y:0,...a}},exports.rectSortingStrategy=d,exports.rectSwappingStrategy=({activeIndex:e,index:t,rects:r,overIndex:n})=>{let i,o;return t===e&&(i=r[t],o=r[n]),t===n&&(i=r[t],o=r[e]),o&&i?{x:o.left-i.left,y:o.top-i.top,scaleX:o.width/i.width,scaleY:o.height/i.height}:null},exports.sortableKeyboardCoordinates=(e,{context:{active:t,droppableContainers:r,collisionRect:i,scrollableAncestors:o}})=>{if(h.includes(e.code)){if(e.preventDefault(),!t||!i)return;const s=[];r.getEnabled().forEach(t=>{if(!t||(null==t?void 0:t.disabled))return;const r=null==t?void 0:t.rect.current;if(r)switch(e.code){case n.KeyboardCode.Down:i.top+i.height<=r.top&&s.push(t);break;case n.KeyboardCode.Up:i.top>=r.top+r.height&&s.push(t);break;case n.KeyboardCode.Left:i.left>=r.left+r.width&&s.push(t);break;case n.KeyboardCode.Right:i.left+i.width<=r.left&&s.push(t)}});const a=n.closestCorners({active:t,collisionRect:i,droppableContainers:s,pointerCoordinates:null}),d=n.getFirstCollision(a,"id");if(null!=d){const e=r.get(d),t=null==e?void 0:e.node.current,s=null==e?void 0:e.rect.current;if(t&&s){const e=n.getScrollableAncestors(t).some((e,t)=>o[t]!==e)?{x:0,y:0}:{x:i.width-s.width,y:i.height-s.height};return{x:s.left-e.x,y:s.top-e.y}}}}},exports.useSortable=function({animateLayoutChanges:e=f,attributes:r,disabled:o,data:a,getNewIndex:d=u,id:c,strategy:h,resizeObserverConfig:v,transition:I=x}){const{items:y,containerId:b,activeIndex:m,disableTransforms:w,sortedRects:C,overIndex:S,useDragOverlay:R,strategy:D}=t.useContext(l),O=y.indexOf(c),N=t.useMemo(()=>({sortable:{containerId:b,index:O,items:y},...a}),[b,a,O,y]),K=t.useMemo(()=>y.slice(y.indexOf(c)),[y,c]),{rect:E,node:L,isOver:M,setNodeRef:T}=n.useDroppable({id:c,data:N,resizeObserverConfig:{updateMeasurementsFor:K,...v}}),{active:k,activeNodeRect:q,attributes:A,setNodeRef:X,listeners:Y,isDragging:j,over:z,transform:F}=n.useDraggable({id:c,data:N,attributes:{...p,...r},disabled:o}),U=i.useCombinedRefs(T,X),B=Boolean(k),P=B&&!w&&s(m)&&s(S),_=!R&&j,G=_&&P?F:null,H=P?null!=G?G:(null!=h?h:D)({rects:C,activeNodeRect:q,activeIndex:m,overIndex:S,index:O}):null,J=s(m)&&s(S)?d({id:c,items:y,activeIndex:m,overIndex:S}):O,Q=null==k?void 0:k.id,V=t.useRef({activeId:Q,items:y,newIndex:J,containerId:b}),W=y!==V.current.items,Z=e({active:k,containerId:b,isDragging:j,isSorting:B,id:c,index:O,items:y,newIndex:V.current.newIndex,previousItems:V.current.items,previousContainerId:V.current.containerId,transition:I,wasDragging:null!=V.current.activeId}),$=function({disabled:e,index:r,node:o,rect:s}){const[a,d]=t.useState(null),c=t.useRef(r);return i.useIsomorphicLayoutEffect(()=>{if(!e&&r!==c.current&&o.current){const e=s.current;if(e){const t=n.getClientRect(o.current,{ignoreTransform:!0}),r={x:e.left-t.left,y:e.top-t.top,scaleX:e.width/t.width,scaleY:e.height/t.height};(r.x||r.y)&&d(r)}}r!==c.current&&(c.current=r)},[e,r,o,s]),t.useEffect(()=>{a&&requestAnimationFrame(()=>{d(null)})},[a]),a}({disabled:!Z,index:O,node:L,rect:E});return t.useEffect(()=>{B&&V.current.newIndex!==J&&(V.current.newIndex=J),b!==V.current.containerId&&(V.current.containerId=b),y!==V.current.items&&(V.current.items=y),Q!==V.current.activeId&&(V.current.activeId=Q)},[Q,B,J,b,y]),{active:k,activeIndex:m,attributes:A,rect:E,index:O,newIndex:J,items:y,isOver:M,isSorting:B,isDragging:j,listeners:Y,node:L,overIndex:S,over:z,setNodeRef:U,setDroppableNodeRef:T,setDraggableNodeRef:X,transform:null!=$?$:H,transition:$||W&&V.current.newIndex===O?g:!_&&I&&(B||Z)?i.CSS.Transition.toString({...I,property:"transform"}):void 0}},exports.verticalListSortingStrategy=({activeIndex:e,activeNodeRect:t,index:r,rects:n,overIndex:i})=>{var o;const s=null!=(o=n[e])?o:t;if(!s)return null;if(r===e){const t=n[i];return t?{x:0,y:e<i?t.top+t.height-(s.top+s.height):t.top-s.top,...c}:null}const a=function(e,t,r){const n=e[t],i=e[t-1],o=e[t+1];return n?r<t?i?n.top-(i.top+i.height):o?o.top-(n.top+n.height):0:o?o.top-(n.top+n.height):i?n.top-(i.top+i.height):0:0}(n,r,e);return r>e&&r<=i?{x:0,y:-s.height-a,...c}:r<e&&r>=i?{x:0,y:s.height+a,...c}:{x:0,y:0,...c}}; | ||
//# sourceMappingURL=sortable.cjs.production.min.js.map |
import React, { useMemo, useRef, useEffect, useState, useContext } from 'react'; | ||
import { useDndContext, getBoundingClientRect, useDroppable, useDraggable, getViewRect, closestCorners, getScrollableAncestors, KeyboardCode } from '@dnd-kit/core'; | ||
import { useDndContext, getClientRect, useDroppable, useDraggable, closestCorners, getFirstCollision, getScrollableAncestors, KeyboardCode } from '@dnd-kit/core'; | ||
import { useUniqueId, useIsomorphicLayoutEffect, CSS, useCombinedRefs } from '@dnd-kit/utilities'; | ||
@@ -24,8 +24,8 @@ | ||
function getSortedRects(items, layoutRects) { | ||
function getSortedRects(items, rects) { | ||
return items.reduce((accumulator, id, index) => { | ||
const layoutRect = layoutRects.get(id); | ||
const rect = rects.get(id); | ||
if (layoutRect) { | ||
accumulator[index] = layoutRect; | ||
if (rect) { | ||
accumulator[index] = rect; | ||
} | ||
@@ -47,3 +47,3 @@ | ||
const horizontalListSortingStrategy = ({ | ||
layoutRects, | ||
rects, | ||
activeNodeRect: fallbackActiveRect, | ||
@@ -54,5 +54,5 @@ activeIndex, | ||
}) => { | ||
var _layoutRects$activeIn; | ||
var _rects$activeIndex; | ||
const activeNodeRect = (_layoutRects$activeIn = layoutRects[activeIndex]) != null ? _layoutRects$activeIn : fallbackActiveRect; | ||
const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect; | ||
@@ -63,6 +63,6 @@ if (!activeNodeRect) { | ||
const itemGap = getItemGap(layoutRects, index, activeIndex); | ||
const itemGap = getItemGap(rects, index, activeIndex); | ||
if (index === activeIndex) { | ||
const newIndexRect = layoutRects[overIndex]; | ||
const newIndexRect = rects[overIndex]; | ||
@@ -74,3 +74,3 @@ if (!newIndexRect) { | ||
return { | ||
x: activeIndex < overIndex ? newIndexRect.offsetLeft + newIndexRect.width - (activeNodeRect.offsetLeft + activeNodeRect.width) : newIndexRect.offsetLeft - activeNodeRect.offsetLeft, | ||
x: activeIndex < overIndex ? newIndexRect.left + newIndexRect.width - (activeNodeRect.left + activeNodeRect.width) : newIndexRect.left - activeNodeRect.left, | ||
y: 0, | ||
@@ -104,6 +104,6 @@ ...defaultScale | ||
function getItemGap(layoutRects, index, activeIndex) { | ||
const currentRect = layoutRects[index]; | ||
const previousRect = layoutRects[index - 1]; | ||
const nextRect = layoutRects[index + 1]; | ||
function getItemGap(rects, index, activeIndex) { | ||
const currentRect = rects[index]; | ||
const previousRect = rects[index - 1]; | ||
const nextRect = rects[index + 1]; | ||
@@ -115,10 +115,10 @@ if (!currentRect || !previousRect && !nextRect) { | ||
if (activeIndex < index) { | ||
return previousRect ? currentRect.offsetLeft - (previousRect.offsetLeft + previousRect.width) : nextRect.offsetLeft - (currentRect.offsetLeft + currentRect.width); | ||
return previousRect ? currentRect.left - (previousRect.left + previousRect.width) : nextRect.left - (currentRect.left + currentRect.width); | ||
} | ||
return nextRect ? nextRect.offsetLeft - (currentRect.offsetLeft + currentRect.width) : currentRect.offsetLeft - (previousRect.offsetLeft + previousRect.width); | ||
return nextRect ? nextRect.left - (currentRect.left + currentRect.width) : currentRect.left - (previousRect.left + previousRect.width); | ||
} | ||
const rectSortingStrategy = ({ | ||
layoutRects, | ||
rects, | ||
activeIndex, | ||
@@ -128,4 +128,4 @@ overIndex, | ||
}) => { | ||
const newRects = arrayMove(layoutRects, overIndex, activeIndex); | ||
const oldRect = layoutRects[index]; | ||
const newRects = arrayMove(rects, overIndex, activeIndex); | ||
const oldRect = rects[index]; | ||
const newRect = newRects[index]; | ||
@@ -138,4 +138,4 @@ | ||
return { | ||
x: newRect.offsetLeft - oldRect.offsetLeft, | ||
y: newRect.offsetTop - oldRect.offsetTop, | ||
x: newRect.left - oldRect.left, | ||
y: newRect.top - oldRect.top, | ||
scaleX: newRect.width / oldRect.width, | ||
@@ -149,3 +149,3 @@ scaleY: newRect.height / oldRect.height | ||
index, | ||
layoutRects, | ||
rects, | ||
overIndex | ||
@@ -157,9 +157,9 @@ }) => { | ||
if (index === activeIndex) { | ||
oldRect = layoutRects[index]; | ||
newRect = layoutRects[overIndex]; | ||
oldRect = rects[index]; | ||
newRect = rects[overIndex]; | ||
} | ||
if (index === overIndex) { | ||
oldRect = layoutRects[index]; | ||
newRect = layoutRects[activeIndex]; | ||
oldRect = rects[index]; | ||
newRect = rects[activeIndex]; | ||
} | ||
@@ -172,4 +172,4 @@ | ||
return { | ||
x: newRect.offsetLeft - oldRect.offsetLeft, | ||
y: newRect.offsetTop - oldRect.offsetTop, | ||
x: newRect.left - oldRect.left, | ||
y: newRect.top - oldRect.top, | ||
scaleX: newRect.width / oldRect.width, | ||
@@ -189,8 +189,8 @@ scaleY: newRect.height / oldRect.height | ||
index, | ||
layoutRects, | ||
rects, | ||
overIndex | ||
}) => { | ||
var _layoutRects$activeIn; | ||
var _rects$activeIndex; | ||
const activeNodeRect = (_layoutRects$activeIn = layoutRects[activeIndex]) != null ? _layoutRects$activeIn : fallbackActiveRect; | ||
const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect; | ||
@@ -202,3 +202,3 @@ if (!activeNodeRect) { | ||
if (index === activeIndex) { | ||
const overIndexRect = layoutRects[overIndex]; | ||
const overIndexRect = rects[overIndex]; | ||
@@ -211,3 +211,3 @@ if (!overIndexRect) { | ||
x: 0, | ||
y: activeIndex < overIndex ? overIndexRect.offsetTop + overIndexRect.height - (activeNodeRect.offsetTop + activeNodeRect.height) : overIndexRect.offsetTop - activeNodeRect.offsetTop, | ||
y: activeIndex < overIndex ? overIndexRect.top + overIndexRect.height - (activeNodeRect.top + activeNodeRect.height) : overIndexRect.top - activeNodeRect.top, | ||
...defaultScale$1 | ||
@@ -217,3 +217,3 @@ }; | ||
const itemGap = getItemGap$1(layoutRects, index, activeIndex); | ||
const itemGap = getItemGap$1(rects, index, activeIndex); | ||
@@ -243,6 +243,6 @@ if (index > activeIndex && index <= overIndex) { | ||
function getItemGap$1(layoutRects, index, activeIndex) { | ||
const currentRect = layoutRects[index]; | ||
const previousRect = layoutRects[index - 1]; | ||
const nextRect = layoutRects[index + 1]; | ||
function getItemGap$1(clientRects, index, activeIndex) { | ||
const currentRect = clientRects[index]; | ||
const previousRect = clientRects[index - 1]; | ||
const nextRect = clientRects[index + 1]; | ||
@@ -254,6 +254,6 @@ if (!currentRect) { | ||
if (activeIndex < index) { | ||
return previousRect ? currentRect.offsetTop - (previousRect.offsetTop + previousRect.height) : nextRect ? nextRect.offsetTop - (currentRect.offsetTop + currentRect.height) : 0; | ||
return previousRect ? currentRect.top - (previousRect.top + previousRect.height) : nextRect ? nextRect.top - (currentRect.top + currentRect.height) : 0; | ||
} | ||
return nextRect ? nextRect.offsetTop - (currentRect.offsetTop + currentRect.height) : previousRect ? currentRect.offsetTop - (previousRect.offsetTop + previousRect.height) : 0; | ||
return nextRect ? nextRect.top - (currentRect.top + currentRect.height) : previousRect ? currentRect.top - (previousRect.top + previousRect.height) : 0; | ||
} | ||
@@ -270,6 +270,3 @@ | ||
sortedRects: [], | ||
strategy: rectSortingStrategy, | ||
wasDragging: { | ||
current: false | ||
} | ||
strategy: rectSortingStrategy | ||
}); | ||
@@ -287,4 +284,4 @@ function SortableContext({ | ||
over, | ||
recomputeLayouts, | ||
willRecomputeLayouts | ||
measureDroppableContainers, | ||
measuringScheduled | ||
} = useDndContext(); | ||
@@ -295,5 +292,3 @@ const containerId = useUniqueId(ID_PREFIX, id); | ||
const isDragging = active != null; | ||
const wasDragging = useRef(false); | ||
const activeIndex = active ? items.indexOf(active.id) : -1; | ||
const isSorting = activeIndex !== -1; | ||
const overIndex = over ? items.indexOf(over.id) : -1; | ||
@@ -305,16 +300,9 @@ const previousItemsRef = useRef(items); | ||
useIsomorphicLayoutEffect(() => { | ||
if (itemsHaveChanged && isSorting && !willRecomputeLayouts) { | ||
// To-do: Add partial recompution of only subset of rects | ||
recomputeLayouts(); | ||
if (itemsHaveChanged && isDragging && !measuringScheduled) { | ||
measureDroppableContainers(items); | ||
} | ||
}, [itemsHaveChanged, isSorting, recomputeLayouts, willRecomputeLayouts]); | ||
}, [itemsHaveChanged, items, isDragging, measureDroppableContainers, measuringScheduled]); | ||
useEffect(() => { | ||
previousItemsRef.current = items; | ||
}, [items]); | ||
useEffect(() => { | ||
const timeoutId = setTimeout(() => { | ||
wasDragging.current = isDragging; | ||
}, 100); | ||
return () => clearTimeout(timeoutId); | ||
}, [isDragging]); | ||
const contextValue = useMemo(() => ({ | ||
@@ -328,5 +316,4 @@ activeIndex, | ||
sortedRects, | ||
strategy, | ||
wasDragging | ||
}), [activeIndex, containerId, disableTransforms, items, overIndex, sortedRects, useDragOverlay, strategy, wasDragging]); | ||
strategy | ||
}), [activeIndex, containerId, disableTransforms, items, overIndex, sortedRects, useDragOverlay, strategy]); | ||
return React.createElement(Context.Provider, { | ||
@@ -404,6 +391,8 @@ value: contextValue | ||
if (initial) { | ||
const current = getBoundingClientRect(node.current); | ||
const current = getClientRect(node.current, { | ||
ignoreTransform: true | ||
}); | ||
const delta = { | ||
x: initial.offsetLeft - current.offsetLeft, | ||
y: initial.offsetTop - current.offsetTop, | ||
x: initial.left - current.left, | ||
y: initial.top - current.top, | ||
scaleX: initial.width / current.width, | ||
@@ -441,2 +430,3 @@ scaleY: initial.height / current.height | ||
strategy: localStrategy, | ||
resizeObserverConfig, | ||
transition = defaultTransition | ||
@@ -452,4 +442,3 @@ }) { | ||
useDragOverlay, | ||
strategy: globalStrategy, | ||
wasDragging | ||
strategy: globalStrategy | ||
} = useContext(Context); | ||
@@ -465,9 +454,15 @@ const index = items.indexOf(id); | ||
}), [containerId, customData, index, items]); | ||
const itemsAfterCurrentSortable = useMemo(() => items.slice(items.indexOf(id)), [items, id]); | ||
const { | ||
rect, | ||
node, | ||
isOver, | ||
setNodeRef: setDroppableNodeRef | ||
} = useDroppable({ | ||
id, | ||
data | ||
data, | ||
resizeObserverConfig: { | ||
updateMeasurementsFor: itemsAfterCurrentSortable, | ||
...resizeObserverConfig | ||
} | ||
}); | ||
@@ -477,3 +472,2 @@ const { | ||
activeNodeRect, | ||
activatorEvent, | ||
attributes, | ||
@@ -495,3 +489,3 @@ setNodeRef: setDraggableNodeRef, | ||
const isSorting = Boolean(active); | ||
const displaceItem = isSorting && wasDragging.current && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex); | ||
const displaceItem = isSorting && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex); | ||
const shouldDisplaceDragSource = !useDragOverlay && isDragging; | ||
@@ -501,3 +495,3 @@ const dragSourceDisplacement = shouldDisplaceDragSource && displaceItem ? transform : null; | ||
const finalTransform = displaceItem ? dragSourceDisplacement != null ? dragSourceDisplacement : strategy({ | ||
layoutRects: sortedRects, | ||
rects: sortedRects, | ||
activeNodeRect, | ||
@@ -514,6 +508,10 @@ activeIndex, | ||
}) : index; | ||
const prevItems = useRef(items); | ||
const itemsHaveChanged = items !== prevItems.current; | ||
const prevNewIndex = useRef(newIndex); | ||
const previousContainerId = useRef(containerId); | ||
const activeId = active == null ? void 0 : active.id; | ||
const previous = useRef({ | ||
activeId, | ||
items, | ||
newIndex, | ||
containerId | ||
}); | ||
const itemsHaveChanged = items !== previous.current.items; | ||
const shouldAnimateLayoutChanges = animateLayoutChanges({ | ||
@@ -527,7 +525,7 @@ active, | ||
items, | ||
newIndex: prevNewIndex.current, | ||
previousItems: prevItems.current, | ||
previousContainerId: previousContainerId.current, | ||
newIndex: previous.current.newIndex, | ||
previousItems: previous.current.items, | ||
previousContainerId: previous.current.containerId, | ||
transition, | ||
wasDragging: wasDragging.current | ||
wasDragging: previous.current.activeId != null | ||
}); | ||
@@ -541,20 +539,27 @@ const derivedTransform = useDerivedTransform({ | ||
useEffect(() => { | ||
if (isSorting && prevNewIndex.current !== newIndex) { | ||
prevNewIndex.current = newIndex; | ||
if (isSorting && previous.current.newIndex !== newIndex) { | ||
previous.current.newIndex = newIndex; | ||
} | ||
if (containerId !== previousContainerId.current) { | ||
previousContainerId.current = containerId; | ||
if (containerId !== previous.current.containerId) { | ||
previous.current.containerId = containerId; | ||
} | ||
if (items !== prevItems.current) { | ||
prevItems.current = items; | ||
if (items !== previous.current.items) { | ||
previous.current.items = items; | ||
} | ||
}, [isSorting, newIndex, containerId, items]); | ||
if (activeId !== previous.current.activeId) { | ||
previous.current.activeId = activeId; | ||
} | ||
}, [activeId, isSorting, newIndex, containerId, items]); | ||
return { | ||
active, | ||
activeIndex, | ||
attributes, | ||
activatorEvent, | ||
rect, | ||
index, | ||
newIndex, | ||
items, | ||
isOver, | ||
isSorting, | ||
@@ -576,3 +581,3 @@ isDragging, | ||
derivedTransform || // Or to prevent items jumping to back to their "new" position when items change | ||
itemsHaveChanged && prevNewIndex.current === index) { | ||
itemsHaveChanged && previous.current.newIndex === index) { | ||
return disabledTransition; | ||
@@ -600,3 +605,3 @@ } | ||
droppableContainers, | ||
translatedRect, | ||
collisionRect, | ||
scrollableAncestors | ||
@@ -608,3 +613,3 @@ } | ||
if (!active || !translatedRect) { | ||
if (!active || !collisionRect) { | ||
return; | ||
@@ -619,19 +624,12 @@ } | ||
const node = entry == null ? void 0 : entry.node.current; | ||
const rect = entry == null ? void 0 : entry.rect.current; | ||
if (!node) { | ||
if (!rect) { | ||
return; | ||
} | ||
const rect = getViewRect(node); | ||
const container = { ...entry, | ||
rect: { | ||
current: rect | ||
} | ||
}; | ||
switch (event.code) { | ||
case KeyboardCode.Down: | ||
if (translatedRect.top + translatedRect.height <= rect.top) { | ||
filteredContainers.push(container); | ||
if (collisionRect.top + collisionRect.height <= rect.top) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -642,4 +640,4 @@ | ||
case KeyboardCode.Up: | ||
if (translatedRect.top >= rect.top + rect.height) { | ||
filteredContainers.push(container); | ||
if (collisionRect.top >= rect.top + rect.height) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -650,4 +648,4 @@ | ||
case KeyboardCode.Left: | ||
if (translatedRect.left >= rect.left + rect.width) { | ||
filteredContainers.push(container); | ||
if (collisionRect.left >= rect.left + rect.width) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -658,4 +656,4 @@ | ||
case KeyboardCode.Right: | ||
if (translatedRect.left + translatedRect.width <= rect.left) { | ||
filteredContainers.push(container); | ||
if (collisionRect.left + collisionRect.width <= rect.left) { | ||
filteredContainers.push(entry); | ||
} | ||
@@ -666,17 +664,18 @@ | ||
}); | ||
const closestId = closestCorners({ | ||
const collisions = closestCorners({ | ||
active, | ||
collisionRect: translatedRect, | ||
droppableContainers: filteredContainers | ||
collisionRect: collisionRect, | ||
droppableContainers: filteredContainers, | ||
pointerCoordinates: null | ||
}); | ||
const closestId = getFirstCollision(collisions, 'id'); | ||
if (closestId) { | ||
var _droppableContainers$; | ||
if (closestId != null) { | ||
const newDroppable = droppableContainers.get(closestId); | ||
const newNode = newDroppable == null ? void 0 : newDroppable.node.current; | ||
const newRect = newDroppable == null ? void 0 : newDroppable.rect.current; | ||
const newNode = (_droppableContainers$ = droppableContainers.get(closestId)) == null ? void 0 : _droppableContainers$.node.current; | ||
if (newNode) { | ||
if (newNode && newRect) { | ||
const newScrollAncestors = getScrollableAncestors(newNode); | ||
const hasDifferentScrollAncestors = newScrollAncestors.some((element, index) => scrollableAncestors[index] !== element); | ||
const newRect = getViewRect(newNode); | ||
const offset = hasDifferentScrollAncestors ? { | ||
@@ -686,4 +685,4 @@ x: 0, | ||
} : { | ||
x: translatedRect.width - newRect.width, | ||
y: translatedRect.height - newRect.height | ||
x: collisionRect.width - newRect.width, | ||
y: collisionRect.height - newRect.height | ||
}; | ||
@@ -690,0 +689,0 @@ const newCoordinates = { |
@@ -1,9 +0,9 @@ | ||
import type { LayoutRect, ViewRect } from '@dnd-kit/core'; | ||
import type { ClientRect } from '@dnd-kit/core'; | ||
import type { Transform } from '@dnd-kit/utilities'; | ||
export declare type SortingStrategy = (args: { | ||
activeNodeRect: ViewRect | null; | ||
activeNodeRect: ClientRect | null; | ||
activeIndex: number; | ||
index: number; | ||
layoutRects: LayoutRect[]; | ||
rects: ClientRect[]; | ||
overIndex: number; | ||
}) => Transform | null; |
@@ -1,2 +0,2 @@ | ||
import type { LayoutRect, UniqueIdentifier, UseDndContextReturnValue } from '@dnd-kit/core'; | ||
export declare function getSortedRects(items: UniqueIdentifier[], layoutRects: UseDndContextReturnValue['droppableRects']): LayoutRect[]; | ||
import type { ClientRect, UniqueIdentifier, UseDndContextReturnValue } from '@dnd-kit/core'; | ||
export declare function getSortedRects(items: UniqueIdentifier[], rects: UseDndContextReturnValue['droppableRects']): ClientRect[]; |
{ | ||
"name": "@dnd-kit/sortable", | ||
"version": "5.1.0", | ||
"version": "6.0.0-next-20220101438", | ||
"description": "Official sortable preset and sensors for dnd kit", | ||
@@ -29,3 +29,3 @@ "author": "Claudéric Demers", | ||
"dependencies": { | ||
"@dnd-kit/utilities": "^3.0.0", | ||
"@dnd-kit/utilities": "^3.1.0-next-20220101438", | ||
"tslib": "^2.0.0" | ||
@@ -35,6 +35,6 @@ }, | ||
"react": ">=16.8.0", | ||
"@dnd-kit/core": "^4.0.2" | ||
"@dnd-kit/core": "^5.0.0-next-20220101438" | ||
}, | ||
"devDependencies": { | ||
"@dnd-kit/core": "^4.0.2" | ||
"@dnd-kit/core": "^5.0.0-next-20220101438" | ||
}, | ||
@@ -41,0 +41,0 @@ "publishConfig": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
194178
1372
3
+ Added@dnd-kit/core@5.0.3(transitive)
- Removed@dnd-kit/core@4.0.3(transitive)