Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

svelte-dnd-action

Package Overview
Dependencies
Maintainers
1
Versions
129
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svelte-dnd-action - npm Package Compare versions

Comparing version 0.5.3 to 0.6.0

src/constants.js

3

package.json
{
"name": "svelte-dnd-action",
"svelte": "src/index.js",
"main": "src/index.js",
"scripts": {

@@ -29,3 +30,3 @@ "test": "cypress run"

"description": "*An awesome drag and drop library for Svelte 3 (not using the browser's built-in dnd, thanks god): Rich animations, nested containers, touch support and more *",
"version": "0.5.3",
"version": "0.6.0",
"repository": {

@@ -32,0 +33,0 @@ "type": "git",

# SVELTE DND ACTION [![Known Vulnerabilities](https://snyk.io/test/github/isaacHagoel/svelte-dnd-action/badge.svg?targetFile=package.json)](https://snyk.io/test/github/isaacHagoel/svelte-dnd-action?targetFile=package.json)
This is an implementation of Trello-like drag and drop for Svelte using a custom action. See features list below.
This is a feature-complete implementation of drag and drop for Svelte using a custom action. It supports almost every imaginable drag and drop use-case and is fully accessible.
See full features list below.

@@ -9,3 +10,4 @@ ![dnd_demo2](https://user-images.githubusercontent.com/20507787/81682367-267eb780-9498-11ea-8dbc-5c9582033522.gif)

### Current Status
The library is working well as far as I can tell, but I have not used it in production yet. It is being actively maintained.
The library is working well as far as I can tell, and I am in the process of integrating it into a production system that will be used at scale.
It is being actively maintained.

@@ -15,3 +17,3 @@ ### Features

- Supports horizontal, vertical or any other type of container (it doesn't care much about the shape)
- Supports nested dnd-zones (draggable containers with other draggable elements inside)
- Supports nested dnd-zones (draggable containers with other draggable elements inside, think Trello)
- Rich animations (can be opted out of)

@@ -23,2 +25,3 @@ - Touch support

- Performant and small footprint (no external dependencies, no fluff code)
- Fully accessible (alpha) - keyboard support, aria attributes and assistive instructions for screen readers

@@ -44,3 +47,3 @@ ### Installation

#### Basic Example:
##### Basic Example:

@@ -91,3 +94,3 @@ ```html

#### Input:
##### Input:
An options-object with the following attributes:

@@ -104,3 +107,3 @@ | Name | Type | Required? | Default Value | Description |

#### Output:
##### Output:

@@ -117,2 +120,3 @@ The action dispatches two custom events:

* `id`: the item id of the dragged element
* `source`: will be one of the exported list of SOURCES (Please import if you plan to use): [POINTER, KEYBOARD]

@@ -123,2 +127,28 @@ You have to listen for both events and update the list of items in order for this library to work correctly.

### Accessibility (alpha)
If you want screen-readers to tell the user which item is being dragged and which container it interacts with, **please add `aria-label` on the container and on every draggable item**. The library will take care of the rest.
For example:
```html
<h2>{listName}</h2>
<section aria-label="{listName}" use:dndzone={{items, flipDurationMs}} on:consider={handleDndConsider} on:finalize={handleDndFinalize}>
{#each items as item(item.id)}
<div aria-label="{item.name}" animate:flip="{{duration: flipDurationMs}}">
{item.name}
</div>
{/each}
</section>
```
If you don't provide the aria-labels everything will still work, but the messages to the user will be less informative.
*Note*: in general you probably want to use semantic-html (ex: `ol` and `li` elements rather than `section` and `div`) but the library is screen readers friendly regardless (or at least that's the goal :)).
##### Keyboard support
- Tab into a dnd container to get a description and instructions
- Tab into an item and press the *Space*/*Enter* key to enter dragging-mode. The reader will tell the user a drag has started.
- Use the *arrow keys* while in dragging-mode to change the item's position in the list (down and right are the same, up and left are the same). The reader will tell the user about position changes.
- Tab to another dnd container while in dragging-mode in order to move the item to it (the item will be moved to it when it gets focus). The reader will tell the user that item was added to the new list.
- Press *Space*/*Enter* key while focused on an item, or the *Escape* key anywhere to exit dragging mode. The reader will tell the user that they are no longer dragging.
- Clicking on another item while in drag mode will make it the new drag target. Clicking outside of any draggable will exit dragging-mode (and tell the user)
- Mouse drag and drop can be preformed independently of keyboard dragging (as in an item can be dragged with the mouse while in or out of keyboard initiated dragging-mode)
- Keyboard drag uses the same `consider` (only on drag start) and `finalize` (every time the item is moved) events but only has a subset of the `TRIGGERS`. The same handlers should work fine for both.
### Rules/ assumptions to keep in mind

@@ -125,0 +155,0 @@ * Only one element can be dragged in any given time

@@ -1,251 +0,8 @@

import { observe, unobserve } from './helpers/observer';
import { armWindowScroller, disarmWindowScroller} from "./helpers/windowScroller";
import {
createDraggedElementFrom,
moveDraggedElementToWasDroppedState,
morphDraggedElementToBeLike,
styleDraggable,
styleShadowEl,
styleActiveDropZones,
styleInactiveDropZones,
hideOriginalDragTarget
} from "./helpers/styler";
import { DRAGGED_ENTERED_EVENT_NAME, DRAGGED_LEFT_EVENT_NAME, DRAGGED_LEFT_DOCUMENT_EVENT_NAME, DRAGGED_OVER_INDEX_EVENT_NAME, dispatchConsiderEvent, dispatchFinalizeEvent } from './helpers/dispatcher';
import {areObjectsShallowEqual, toString} from "./helpers/util";
import {dndzone as pointerDndZone} from "./pointerAction";
import {dndzone as keyboardDndZone} from "./keyboardAction";
export const SHADOW_ITEM_MARKER_PROPERTY_NAME = 'isDndShadowItem';
const DEFAULT_DROP_ZONE_TYPE = '--any--';
const MIN_OBSERVATION_INTERVAL_MS = 100;
const MIN_MOVEMENT_BEFORE_DRAG_START_PX = 3;
const DEFAULT_DROP_TARGET_STYLE = {
outline: 'rgba(255, 255, 102, 0.7) solid 2px',
};
let originalDragTarget;
let draggedEl;
let draggedElData;
let draggedElType;
let originDropZone;
let originIndex;
let shadowElIdx;
let shadowElData;
let shadowElDropZone;
let dragStartMousePosition;
let currentMousePosition;
let isWorkingOnPreviousDrag = false;
let finalizingPreviousDrag = false;
// a map from type to a set of drop-zones
const typeToDropZones = new Map();
// important - this is needed because otherwise the config that would be used for everyone is the config of the element that created the event listeners
const dzToConfig = new Map();
// this is needed in order to be able to cleanup old listeners and avoid stale closures issues (as the listener is defined within each zone)
const elToMouseDownListener = new WeakMap();
let ITEM_ID_KEY = "id";
/**
* Allows using another key instead of "id" in the items data. This is global and applies to all dndzones.
* Has to be called when there are no rendered dndzones whatsoever.
* @param {String} newKeyName
* @throws {Error} if it was called when there are rendered dndzones or if it is given the wrong type (not a string)
*/
export function overrideItemIdKeyNameBeforeInitialisingDndZones(newKeyName) {
if (dzToConfig.size > 0) {
throw new Error("can only override the id key before initialising any dndzone");
}
if (typeof newKeyName !== "string") {
throw new Error("item id key has to be a string");
}
console.debug("overriding item id key name", newKeyName)
ITEM_ID_KEY = newKeyName;
}
/* drop-zones registration management */
function registerDropZone(dropZoneEl, type) {
console.debug('registering drop-zone if absent')
if (!typeToDropZones.has(type)) {
typeToDropZones.set(type, new Set());
}
if (!typeToDropZones.get(type).has(dropZoneEl)) {
typeToDropZones.get(type).add(dropZoneEl);
}
}
function unregisterDropZone(dropZoneEl, type) {
typeToDropZones.get(type).delete(dropZoneEl);
if (typeToDropZones.get(type).size === 0) {
typeToDropZones.delete(type);
}
}
/* functions to manage observing the dragged element and trigger custom drag-events */
function watchDraggedElement() {
console.debug('watching dragged element');
armWindowScroller();
const dropZones = typeToDropZones.get(draggedElType);
for (const dz of dropZones) {
dz.addEventListener(DRAGGED_ENTERED_EVENT_NAME, handleDraggedEntered);
dz.addEventListener(DRAGGED_LEFT_EVENT_NAME, handleDraggedLeft);
dz.addEventListener(DRAGGED_OVER_INDEX_EVENT_NAME, handleDraggedIsOverIndex);
}
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
// it is important that we don't have an interval that is faster than the flip duration because it can cause elements to jump bach and forth
const observationIntervalMs = Math.max(MIN_OBSERVATION_INTERVAL_MS, ...Array.from(dropZones.keys()).map(dz => dzToConfig.get(dz).dropAnimationDurationMs));
observe(draggedEl, dropZones, observationIntervalMs * 1.07);
}
function unWatchDraggedElement() {
console.debug('unwatching dragged element');
disarmWindowScroller();
const dropZones = typeToDropZones.get(draggedElType);
for (const dz of dropZones) {
dz.removeEventListener(DRAGGED_ENTERED_EVENT_NAME, handleDraggedEntered);
dz.removeEventListener(DRAGGED_LEFT_EVENT_NAME, handleDraggedLeft);
dz.removeEventListener(DRAGGED_OVER_INDEX_EVENT_NAME, handleDraggedIsOverIndex);
}
window.removeEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
unobserve(draggedEl, dropZones);
}
/* custom drag-events handlers */
function handleDraggedEntered(e) {
console.debug('dragged entered', e.currentTarget, e.detail);
let {items, dropFromOthersDisabled} = dzToConfig.get(e.currentTarget);
if (dropFromOthersDisabled && e.currentTarget !== originDropZone) {
console.debug('drop is currently disabled');
return;
}
// this deals with another svelte related race condition. in rare occasions (super rapid operations) the list hasn't updated yet
items = items.filter(i => i[ITEM_ID_KEY] !== shadowElData[ITEM_ID_KEY])
console.debug(`dragged entered items ${toString(items)}`);
const {index, isProximityBased} = e.detail.indexObj;
shadowElIdx = (isProximityBased && index === e.currentTarget.children.length - 1)? index + 1 : index;
shadowElDropZone = e.currentTarget;
items.splice( shadowElIdx, 0, shadowElData);
dispatchConsiderEvent(e.currentTarget, items, {trigger: TRIGGERS.DRAGGED_ENTERED, id: draggedElData[ITEM_ID_KEY]});
}
function handleDraggedLeft(e) {
console.debug('dragged left', e.currentTarget, e.detail);
const {items, dropFromOthersDisabled} = dzToConfig.get(e.currentTarget);
if (dropFromOthersDisabled && e.currentTarget !== originDropZone) {
console.debug('drop is currently disabled');
return;
}
items.splice(shadowElIdx, 1);
shadowElIdx = undefined;
shadowElDropZone = undefined;
dispatchConsiderEvent(e.currentTarget, items, {trigger: TRIGGERS.DRAGGED_LEFT, id: draggedElData[ITEM_ID_KEY]});
}
function handleDraggedIsOverIndex(e) {
console.debug('dragged is over index', e.currentTarget, e.detail);
const {items, dropFromOthersDisabled} = dzToConfig.get(e.currentTarget);
if (dropFromOthersDisabled && e.currentTarget !== originDropZone) {
console.debug('drop is currently disabled');
return;
}
const {index} = e.detail.indexObj;
items.splice(shadowElIdx, 1);
items.splice( index, 0, shadowElData);
shadowElIdx = index;
dispatchConsiderEvent(e.currentTarget, items, {trigger: TRIGGERS.DRAGGED_OVER_INDEX, id: draggedElData[ITEM_ID_KEY]});
}
/* global mouse/touch-events handlers */
function handleMouseMove(e) {
e.preventDefault();
const c = e.touches? e.touches[0] : e;
currentMousePosition = {x: c.clientX, y: c.clientY};
draggedEl.style.transform = `translate3d(${currentMousePosition.x - dragStartMousePosition.x}px, ${currentMousePosition.y - dragStartMousePosition.y}px, 0)`;
}
function handleDrop() {
console.debug('dropped');
finalizingPreviousDrag = true;
// cleanup
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('touchmove', handleMouseMove);
window.removeEventListener('mouseup', handleDrop);
window.removeEventListener('touchend', handleDrop);
unWatchDraggedElement();
moveDraggedElementToWasDroppedState(draggedEl);
if (!!shadowElDropZone) { // it was dropped in a drop-zone
console.debug('dropped in dz', shadowElDropZone);
let {items, type} = dzToConfig.get(shadowElDropZone);
styleInactiveDropZones(typeToDropZones.get(type), dz => dzToConfig.get(dz).dropTargetStyle);
items = items.map(item => item.hasOwnProperty(SHADOW_ITEM_MARKER_PROPERTY_NAME)? draggedElData : item);
function finalizeWithinZone() {
dispatchFinalizeEvent(shadowElDropZone, items, {trigger: TRIGGERS.DROPPED_INTO_ZONE, id: draggedElData[ITEM_ID_KEY]});
if (shadowElDropZone !== originDropZone) {
// letting the origin drop zone know the element was permanently taken away
dispatchFinalizeEvent(originDropZone, dzToConfig.get(originDropZone).items, {trigger: TRIGGERS.DROPPED_INTO_ANOTHER, id: draggedElData[ITEM_ID_KEY]});
}
shadowElDropZone.children[shadowElIdx].style.visibility = '';
cleanupPostDrop();
}
animateDraggedToFinalPosition(finalizeWithinZone);
}
else { // it needs to return to its place
console.debug('no dz available');
let {items, type} = dzToConfig.get(originDropZone);
styleInactiveDropZones(typeToDropZones.get(type), dz => dzToConfig.get(dz).dropTargetStyle);
items.splice(originIndex, 0, shadowElData);
shadowElDropZone = originDropZone;
shadowElIdx = originIndex;
dispatchConsiderEvent(originDropZone, items, {trigger: TRIGGERS.DROPPED_OUTSIDE_OF_ANY, id: draggedElData[ITEM_ID_KEY]});
function finalizeBackToOrigin() {
items.splice(originIndex, 1, draggedElData);
dispatchFinalizeEvent(originDropZone, items, {trigger: TRIGGERS.DROPPED_OUTSIDE_OF_ANY, id: draggedElData[ITEM_ID_KEY]});
shadowElDropZone.children[shadowElIdx].style.visibility = '';
cleanupPostDrop();
}
window.setTimeout(() => animateDraggedToFinalPosition(finalizeBackToOrigin), 0);
}
}
// helper function for handleDrop
function animateDraggedToFinalPosition(callback) {
const shadowElRect = shadowElDropZone.children[shadowElIdx].getBoundingClientRect();
const newTransform = {
x: shadowElRect.left - parseFloat(draggedEl.style.left),
y: shadowElRect.top - parseFloat(draggedEl.style.top)
};
const {dropAnimationDurationMs} = dzToConfig.get(shadowElDropZone);
const transition = `transform ${dropAnimationDurationMs}ms ease`
draggedEl.style.transition = draggedEl.style.transition? draggedEl.style.transition + "," + transition : transition;
draggedEl.style.transform = `translate3d(${newTransform.x}px, ${newTransform.y}px, 0)`;
window.setTimeout(callback, dropAnimationDurationMs);
}
/* cleanup */
function cleanupPostDrop() {
draggedEl.remove();
originalDragTarget.remove();
draggedEl = undefined;
originalDragTarget = undefined;
draggedElData = undefined;
draggedElType = undefined;
originDropZone = undefined;
originIndex = undefined;
shadowElData = undefined;
shadowElIdx = undefined;
shadowElDropZone = undefined;
dragStartMousePosition = undefined;
currentMousePosition = undefined;
isWorkingOnPreviousDrag = false;
finalizingPreviousDrag = false;
}
export const TRIGGERS = {
DRAG_STARTED: "dragStarted",
DRAGGED_ENTERED: DRAGGED_ENTERED_EVENT_NAME,
DRAGGED_OVER_INDEX: DRAGGED_OVER_INDEX_EVENT_NAME,
DRAGGED_LEFT: DRAGGED_LEFT_EVENT_NAME,
DROPPED_INTO_ZONE: "droppedIntoZone",
DROPPED_INTO_ANOTHER: "droppedIntoAnother",
DROPPED_OUTSIDE_OF_ANY: "droppedOutsideOfAny"
};
/**
* A Svelte custom action to turn any container to a dnd zone and all of its direct children to draggables
* dispatches two events that the container is expected to react to by modifying its list of items,
* Supports mouse, touch and keyboard interactions.
* Dispatches two events that the container is expected to react to by modifying its list of items,
* which will then feed back in to this action via the update function

@@ -257,2 +14,6 @@ *

* @property {number} [flipDurationMs] - if the list animated using flip (recommended), specifies the flip duration such that everything syncs with it without conflict, defaults to zero
* @property {boolean} [dragDisabled]
* @property {boolean} [dropFromOthersDisabled]
* @property {Object} [dragTargetStyle]
* @property {Function} [transformDraggedElement]
* @param {HTMLElement} node - the element to enhance

@@ -263,187 +24,14 @@ * @param {Options} options

export function dndzone(node, options) {
const config = {
items: undefined,
type: DEFAULT_DROP_ZONE_TYPE,
flipDurationMs: 0,
dragDisabled: false,
dropFromOthersDisabled: false,
dropTargetStyle: DEFAULT_DROP_TARGET_STYLE,
transformDraggedElement : () => {}
};
console.debug(`dndzone good to go options: ${toString(options)}, config: ${toString(config)}`, {node});
let elToIdx = new Map();
function addMaybeListeners() {
window.addEventListener('mousemove', handleMouseMoveMaybeDragStart, {passive: false});
window.addEventListener('touchmove', handleMouseMoveMaybeDragStart, {passive: false, capture: false});
window.addEventListener('mouseup', handleFalseAlarm, {passive: false});
window.addEventListener('touchend', handleFalseAlarm, {passive: false});
}
function removeMaybeListeners() {
window.removeEventListener('mousemove', handleMouseMoveMaybeDragStart);
window.removeEventListener('touchmove', handleMouseMoveMaybeDragStart);
window.removeEventListener('mouseup', handleFalseAlarm);
window.removeEventListener('touchend', handleFalseAlarm);
}
function handleFalseAlarm() {
removeMaybeListeners();
originalDragTarget = undefined;
dragStartMousePosition = undefined;
currentMousePosition = undefined;
}
function handleMouseMoveMaybeDragStart(e) {
e.preventDefault();
const c = e.touches? e.touches[0] : e;
currentMousePosition = {x: c.clientX, y: c.clientY};
if (Math.abs(currentMousePosition.x - dragStartMousePosition.x) >= MIN_MOVEMENT_BEFORE_DRAG_START_PX || Math.abs(currentMousePosition.y - dragStartMousePosition.y) >= MIN_MOVEMENT_BEFORE_DRAG_START_PX) {
removeMaybeListeners();
handleDragStart(originalDragTarget);
}
}
function handleMouseDown(e) {
// prevents responding to any button but left click which equals 0 (which is falsy)
if (e.button) {
console.debug(`ignoring none left click button: ${e.button}`);
return;
}
if (isWorkingOnPreviousDrag) {
console.debug('cannot start a new drag before finalizing previous one');
return;
}
e.stopPropagation();
const c = e.touches? e.touches[0] : e;
dragStartMousePosition = {x: c.clientX, y:c.clientY};
currentMousePosition = {...dragStartMousePosition};
originalDragTarget = e.currentTarget;
addMaybeListeners();
}
function handleDragStart() {
console.debug(`drag start config: ${toString(config)}`, originalDragTarget);
isWorkingOnPreviousDrag = true;
// initialising globals
const currentIdx = elToIdx.get(originalDragTarget);
originIndex = currentIdx;
originDropZone = originalDragTarget.parentElement;
const {items, type} = config;
draggedElData = {...items[currentIdx]};
draggedElType = type;
shadowElData = {...draggedElData, [SHADOW_ITEM_MARKER_PROPERTY_NAME]: true};
// creating the draggable element
draggedEl = createDraggedElementFrom(originalDragTarget);
// We will keep the original dom node in the dom because touch events keep firing on it, we want to re-add it after Svelte removes it
function keepOriginalElementInDom() {
const {items: itemsNow} = config;
if (!draggedEl.parentElement && (!itemsNow[originIndex] || draggedElData[ITEM_ID_KEY] !== itemsNow[originIndex][ITEM_ID_KEY])) {
document.body.appendChild(draggedEl);
watchDraggedElement();
hideOriginalDragTarget(originalDragTarget);
document.body.appendChild(originalDragTarget);
} else {
window.requestAnimationFrame(keepOriginalElementInDom);
}
}
window.requestAnimationFrame(keepOriginalElementInDom);
styleActiveDropZones(
Array.from(typeToDropZones.get(config.type))
.filter(dz => dz === originDropZone || !dzToConfig.get(dz).dropFromOthersDisabled),
dz => dzToConfig.get(dz).dropTargetStyle,
);
// removing the original element by removing its data entry
items.splice(currentIdx, 1);
dispatchConsiderEvent(originDropZone, items, {trigger: TRIGGERS.DRAG_STARTED, id: draggedElData[ITEM_ID_KEY]});
// handing over to global handlers - starting to watch the element
window.addEventListener('mousemove', handleMouseMove, {passive: false});
window.addEventListener('touchmove', handleMouseMove, {passive: false, capture: false});
window.addEventListener('mouseup', handleDrop, {passive: false});
window.addEventListener('touchend', handleDrop, {passive: false});
}
function configure({
items = undefined,
flipDurationMs:dropAnimationDurationMs = 0,
type: newType = DEFAULT_DROP_ZONE_TYPE,
dragDisabled = false,
dropFromOthersDisabled = false,
dropTargetStyle = DEFAULT_DROP_TARGET_STYLE,
transformDraggedElement = () => {},
...rest
}) {
if (Object.keys(rest).length > 0) {
console.warn(`dndzone will ignore unknown options`, rest);
}
if (!items) {
throw new Error("no 'items' key provided to dndzone");
}
const itemWithMissingId = items.find(item => !item.hasOwnProperty(ITEM_ID_KEY));
if (itemWithMissingId) {
throw new Error(`missing '${ITEM_ID_KEY}' property for item ${toString(itemWithMissingId)}`);
}
config.dropAnimationDurationMs = dropAnimationDurationMs;
if (config.type && newType !== config.type) {
unregisterDropZone(node, config.type);
}
config.type = newType;
registerDropZone(node, newType);
config.items = [...items];
config.dragDisabled = dragDisabled;
config.transformDraggedElement = transformDraggedElement;
// realtime update for dropTargetStyle
if (isWorkingOnPreviousDrag && !finalizingPreviousDrag && !areObjectsShallowEqual(dropTargetStyle, config.dropTargetStyle)) {
styleInactiveDropZones([node], () => config.dropTargetStyle);
styleActiveDropZones([node], () => dropTargetStyle);
}
config.dropTargetStyle = dropTargetStyle;
// realtime update for dropFromOthersDisabled
if (isWorkingOnPreviousDrag && config.dropFromOthersDisabled !== dropFromOthersDisabled) {
if (dropFromOthersDisabled) {
styleInactiveDropZones([node], dz => dzToConfig.get(dz).dropTargetStyle);
} else {
styleActiveDropZones([node], dz => dzToConfig.get(dz).dropTargetStyle);
}
}
config.dropFromOthersDisabled = dropFromOthersDisabled;
dzToConfig.set(node, config);
for (let idx = 0; idx < node.children.length; idx++) {
const draggableEl = node.children[idx];
styleDraggable(draggableEl, dragDisabled);
if (config.items[idx].hasOwnProperty(SHADOW_ITEM_MARKER_PROPERTY_NAME)) {
morphDraggedElementToBeLike(draggedEl, draggableEl, currentMousePosition.x, currentMousePosition.y, () => config.transformDraggedElement(draggedEl, draggedElData, idx));
styleShadowEl(draggableEl);
continue;
}
draggableEl.removeEventListener('mousedown', elToMouseDownListener.get(draggableEl));
draggableEl.removeEventListener('touchstart', elToMouseDownListener.get(draggableEl));
if (!dragDisabled) {
draggableEl.addEventListener('mousedown', handleMouseDown);
draggableEl.addEventListener('touchstart', handleMouseDown);
elToMouseDownListener.set(draggableEl, handleMouseDown);
}
// updating the idx
elToIdx.set(draggableEl, idx);
}
}
configure(options);
return ({
update: (newOptions) => {
console.debug(`dndzone will update newOptions: ${toString(newOptions)}`);
configure(newOptions);
const pointerZone = pointerDndZone(node, options);
const keyboardZone = keyboardDndZone(node, options);
return {
update: newOptions => {
pointerZone.update(newOptions);
keyboardZone.update(newOptions);
},
destroy: () => {
console.debug("dndzone will destroy");
unregisterDropZone(node, config.type);
dzToConfig.delete(node);
pointerZone.destroy();
keyboardZone.destroy();
}
});
}
}
}

@@ -9,2 +9,3 @@ // external events

* @property {string} id
* @property {string} source
* @param {Node} el

@@ -11,0 +12,0 @@ * @param {Array} items

@@ -1,1 +0,2 @@

export { dndzone, TRIGGERS, SHADOW_ITEM_MARKER_PROPERTY_NAME, overrideItemIdKeyNameBeforeInitialisingDndZones } from './action.js';
export { dndzone } from './action.js';
export {TRIGGERS, SOURCES, SHADOW_ITEM_MARKER_PROPERTY_NAME, overrideItemIdKeyNameBeforeInitialisingDndZones} from './constants';
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc