svelte-dnd-action 0.9.45 → 0.9.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +113 -0
- package/dist/index.mjs +112 -1
- package/package.json +1 -1
- package/src/index.js +1 -0
- package/src/wrappers/simpleStore.js +18 -0
- package/src/wrappers/withDragHandles.js +108 -0
package/README.md
CHANGED
|
@@ -170,6 +170,73 @@ If you want to implement your own custom screen-reader alerts, roles and instruc
|
|
|
170
170
|
- 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)
|
|
171
171
|
- Keyboard drag uses the same `consider` (only on drag start) and `finalize` (every time the item is moved) events but share only some of the `TRIGGERS`. The same handlers should work fine for both.
|
|
172
172
|
|
|
173
|
+
### Drag Handles Support
|
|
174
|
+
|
|
175
|
+
Due to popular demand, starting in version 0.9.46 the library exports a wrapper action that greatly improves the ergonomics around using drag handles.
|
|
176
|
+
Notes:
|
|
177
|
+
|
|
178
|
+
- A draggable item within a `dragHandleZone` would not be draggable unless it has an element that uses the `dragHandle` action inside (doesn't have to be a direct child but has to be inside the bounding rect of the item).
|
|
179
|
+
- Don't forget an aria-label on the handle
|
|
180
|
+
Usage:
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<script>
|
|
184
|
+
import {dragHandleZone, dragHandle} from "svelte-dnd-action";
|
|
185
|
+
import {flip} from "svelte/animate";
|
|
186
|
+
|
|
187
|
+
let items = [
|
|
188
|
+
{
|
|
189
|
+
id: 1,
|
|
190
|
+
text: "Item 1"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: 2,
|
|
194
|
+
text: "Item 2"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: 3,
|
|
198
|
+
text: "Item 3"
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
const flipDurationMs = 100;
|
|
202
|
+
|
|
203
|
+
function handleSort(e) {
|
|
204
|
+
items = e.detail.items;
|
|
205
|
+
}
|
|
206
|
+
</script>
|
|
207
|
+
|
|
208
|
+
<style>
|
|
209
|
+
div {
|
|
210
|
+
position: relative;
|
|
211
|
+
height: 1.5em;
|
|
212
|
+
width: 10em;
|
|
213
|
+
text-align: center;
|
|
214
|
+
border: 1px solid black;
|
|
215
|
+
margin: 0.2em;
|
|
216
|
+
padding: 0.3em;
|
|
217
|
+
}
|
|
218
|
+
.handle {
|
|
219
|
+
position: absolute;
|
|
220
|
+
right: 0;
|
|
221
|
+
width: 1em;
|
|
222
|
+
height: 0.5em;
|
|
223
|
+
background-color: grey;
|
|
224
|
+
}
|
|
225
|
+
</style>
|
|
226
|
+
|
|
227
|
+
<h3>Drag Handles</h3>
|
|
228
|
+
<p>Items can be dragged using the grey handles via mouse, touch or keyboard. The text on the items can be selected without starting a drag</p>
|
|
229
|
+
<hr />
|
|
230
|
+
<section use:dragHandleZone="{{ items, flipDurationMs }}" on:consider="{handleSort}" on:finalize="{handleSort}">
|
|
231
|
+
{#each items as item (item.id)}
|
|
232
|
+
<div animate:flip="{{ duration: flipDurationMs }}">
|
|
233
|
+
<div use:dragHandle aria-label="drag-handle for {item.text}" class="handle" />
|
|
234
|
+
<span>{item.text}</span>
|
|
235
|
+
</div>
|
|
236
|
+
{/each}
|
|
237
|
+
</section>
|
|
238
|
+
```
|
|
239
|
+
|
|
173
240
|
### Examples and Recipes
|
|
174
241
|
|
|
175
242
|
- [Super basic, single list, no animation](https://svelte.dev/repl/bbd709b1a00b453e94658392c97a018a?version=3)
|
|
@@ -184,7 +251,7 @@ If you want to implement your own custom screen-reader alerts, roles and instruc
|
|
|
184
251
|
|
|
185
252
|
- [Copy on drag, simple and Dragula like](https://svelte.dev/repl/924b4cc920524065a637fa910fe10193?version=3)
|
|
186
253
|
- [Copy on drop and a drop area with a single slot](https://svelte.dev/repl/b4e120c45c3e48e49a0d637f0cf097d9?version=3)
|
|
187
|
-
- [Drag handles](https://svelte.dev/repl/4949485c5a8f46e7bdbeb73ed565a9c7?version=3), courtesy of @gleuch
|
|
254
|
+
- [Drag handles](https://svelte.dev/repl/4949485c5a8f46e7bdbeb73ed565a9c7?version=3), legacy - before version 0.9.46, courtesy of @gleuch
|
|
188
255
|
- [Interaction (save/get items) with an asynchronous server](https://svelte.dev/repl/964fdac31cb9496da9ded35002300abb?version=3)
|
|
189
256
|
- [Unsortable lists with custom aria instructions](https://svelte.dev/repl/e020ea1051dc4ae3ac2b697064f234bc?version=3)
|
|
190
257
|
- [Crazy nesting](https://svelte.dev/repl/fe8c9eca04f9417a94a8b6041df77139?version=3), courtesy of @zahachtah
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,27 @@ export declare function dndzone<T extends Item>(
|
|
|
16
16
|
destroy: () => void;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* A wrapper action to make it easy to work with drag handles.
|
|
21
|
+
* When using this you must also use the 'dragHandle' action on an element inside each item within the zone.
|
|
22
|
+
*/
|
|
23
|
+
export declare function dragHandleZone<T extends Item>(node: HTMLElement, options: Options<T>): ActionReturn<Options<T>, DndZoneAttributes<T>>;
|
|
24
|
+
export declare function dragHandleZone<T extends Item>(
|
|
25
|
+
node: HTMLElement,
|
|
26
|
+
options: Options<T>
|
|
27
|
+
): {
|
|
28
|
+
update: (newOptions: Options<T>) => void;
|
|
29
|
+
destroy: () => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* This should be used to mark drag handles inside items that belong to a 'dragHandleZone'
|
|
34
|
+
*/
|
|
35
|
+
export declare function dragHandle(node: HTMLElement): {
|
|
36
|
+
update: () => void;
|
|
37
|
+
destroy: () => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
19
40
|
export type TransformDraggedElementFunction = (
|
|
20
41
|
element?: HTMLElement, // the dragged element.
|
|
21
42
|
draggedElementData?: Item, // the data of the item from the items array
|
package/dist/index.js
CHANGED
|
@@ -2524,6 +2524,117 @@
|
|
|
2524
2524
|
}(parseFloat(value));
|
|
2525
2525
|
}
|
|
2526
2526
|
|
|
2527
|
+
function createStore(initialValue) {
|
|
2528
|
+
var _val = initialValue;
|
|
2529
|
+
var subs = new Set();
|
|
2530
|
+
return {
|
|
2531
|
+
get: function get() {
|
|
2532
|
+
return _val;
|
|
2533
|
+
},
|
|
2534
|
+
set: function set(newVal) {
|
|
2535
|
+
_val = newVal;
|
|
2536
|
+
Array.from(subs).forEach(function (cb) {
|
|
2537
|
+
return cb(_val);
|
|
2538
|
+
});
|
|
2539
|
+
},
|
|
2540
|
+
subscribe: function subscribe(cb) {
|
|
2541
|
+
subs.add(cb);
|
|
2542
|
+
cb(_val);
|
|
2543
|
+
},
|
|
2544
|
+
unsubscribe: function unsubscribe(cb) {
|
|
2545
|
+
subs["delete"](cb);
|
|
2546
|
+
}
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
var isItemsDragDisabled = createStore(true);
|
|
2551
|
+
function getAddedOptions() {
|
|
2552
|
+
var isItemsDragDisabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
2553
|
+
return {
|
|
2554
|
+
dragDisabled: isItemsDragDisabled,
|
|
2555
|
+
zoneItemTabIndex: -1
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
/**
|
|
2560
|
+
* This is an action that wraps around the dndzone action to make it easy to work with drag handles
|
|
2561
|
+
* When using this you must also use the 'dragHandle' action (see below) on an element inside each item within the zone
|
|
2562
|
+
* Credit for the idea and initial implementation goes to @gleuch (Greg Leuch) and @geovie (Georg Vienna)
|
|
2563
|
+
*
|
|
2564
|
+
* @param {HTMLElement} node
|
|
2565
|
+
* @param options - will be passed down to the dndzone
|
|
2566
|
+
* @return {{update: (newOptions: Object) => {}, destroy: () => {}}}
|
|
2567
|
+
*/
|
|
2568
|
+
function dragHandleZone(node, options) {
|
|
2569
|
+
var currentOptions = options;
|
|
2570
|
+
var zone = dndzone$2(node, _objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions()));
|
|
2571
|
+
function isItemDisabledCB(isItemsDragDisabled) {
|
|
2572
|
+
zone.update(_objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions(isItemsDragDisabled)));
|
|
2573
|
+
}
|
|
2574
|
+
isItemsDragDisabled.subscribe(isItemDisabledCB);
|
|
2575
|
+
function consider(e) {
|
|
2576
|
+
var _e$detail$info = e.detail.info,
|
|
2577
|
+
source = _e$detail$info.source,
|
|
2578
|
+
trigger = _e$detail$info.trigger;
|
|
2579
|
+
// Ensure dragging is stopped on drag finish via keyboard
|
|
2580
|
+
if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) {
|
|
2581
|
+
isItemsDragDisabled.set(true);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
function finalize(e) {
|
|
2585
|
+
var source = e.detail.info.source;
|
|
2586
|
+
// Ensure dragging is stopped on drag finish via pointer (mouse, touch)
|
|
2587
|
+
if (source === SOURCES.POINTER) {
|
|
2588
|
+
isItemsDragDisabled.set(true);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
node.addEventListener("consider", consider);
|
|
2592
|
+
node.addEventListener("finalize", finalize);
|
|
2593
|
+
return {
|
|
2594
|
+
update: function update(newOptions) {
|
|
2595
|
+
currentOptions = newOptions;
|
|
2596
|
+
zone.update(_objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions(isItemsDragDisabled.get())));
|
|
2597
|
+
},
|
|
2598
|
+
destroy: function destroy() {
|
|
2599
|
+
node.removeEventListener("consider", consider);
|
|
2600
|
+
node.removeEventListener("finalize", finalize);
|
|
2601
|
+
isItemsDragDisabled.unsubscribe(isItemDisabledCB);
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
/**
|
|
2607
|
+
* This should be used to mark drag handles inside items that belong to a 'dragHandleZone' (see above)
|
|
2608
|
+
* @param {HTMLElement} handle
|
|
2609
|
+
* @return {{update: *, destroy: *}}
|
|
2610
|
+
*/
|
|
2611
|
+
function dragHandle(handle) {
|
|
2612
|
+
handle.setAttribute("role", "button");
|
|
2613
|
+
function startDrag(e) {
|
|
2614
|
+
// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
|
|
2615
|
+
e.preventDefault();
|
|
2616
|
+
isItemsDragDisabled.set(false);
|
|
2617
|
+
}
|
|
2618
|
+
function handleKeyDown(e) {
|
|
2619
|
+
if (e.key === "Enter" || e.key === " ") isItemsDragDisabled.set(false);
|
|
2620
|
+
}
|
|
2621
|
+
isItemsDragDisabled.subscribe(function (disabled) {
|
|
2622
|
+
handle.tabIndex = disabled ? 0 : -1;
|
|
2623
|
+
handle.style.cursor = disabled ? "grab" : "grabbing";
|
|
2624
|
+
});
|
|
2625
|
+
handle.addEventListener("mousedown", startDrag);
|
|
2626
|
+
handle.addEventListener("touchstart", startDrag);
|
|
2627
|
+
handle.addEventListener("keydown", handleKeyDown);
|
|
2628
|
+
return {
|
|
2629
|
+
update: function update() {},
|
|
2630
|
+
destroy: function destroy() {
|
|
2631
|
+
handle.removeEventListener("mousedown", startDrag);
|
|
2632
|
+
handle.removeEventListener("touchstart", startDrag);
|
|
2633
|
+
handle.removeEventListener("keydown", handleKeyDown);
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2527
2638
|
exports.DRAGGED_ELEMENT_ID = DRAGGED_ELEMENT_ID;
|
|
2528
2639
|
exports.FEATURE_FLAG_NAMES = FEATURE_FLAG_NAMES;
|
|
2529
2640
|
exports.SHADOW_ITEM_MARKER_PROPERTY_NAME = SHADOW_ITEM_MARKER_PROPERTY_NAME;
|
|
@@ -2532,6 +2643,8 @@
|
|
|
2532
2643
|
exports.TRIGGERS = TRIGGERS;
|
|
2533
2644
|
exports.alertToScreenReader = alertToScreenReader;
|
|
2534
2645
|
exports.dndzone = dndzone$2;
|
|
2646
|
+
exports.dragHandle = dragHandle;
|
|
2647
|
+
exports.dragHandleZone = dragHandleZone;
|
|
2535
2648
|
exports.overrideItemIdKeyNameBeforeInitialisingDndZones = overrideItemIdKeyNameBeforeInitialisingDndZones;
|
|
2536
2649
|
exports.setDebugMode = setDebugMode;
|
|
2537
2650
|
exports.setFeatureFlag = setFeatureFlag;
|
package/dist/index.mjs
CHANGED
|
@@ -2518,4 +2518,115 @@ function isInt(value) {
|
|
|
2518
2518
|
}(parseFloat(value));
|
|
2519
2519
|
}
|
|
2520
2520
|
|
|
2521
|
-
|
|
2521
|
+
function createStore(initialValue) {
|
|
2522
|
+
var _val = initialValue;
|
|
2523
|
+
var subs = new Set();
|
|
2524
|
+
return {
|
|
2525
|
+
get: function get() {
|
|
2526
|
+
return _val;
|
|
2527
|
+
},
|
|
2528
|
+
set: function set(newVal) {
|
|
2529
|
+
_val = newVal;
|
|
2530
|
+
Array.from(subs).forEach(function (cb) {
|
|
2531
|
+
return cb(_val);
|
|
2532
|
+
});
|
|
2533
|
+
},
|
|
2534
|
+
subscribe: function subscribe(cb) {
|
|
2535
|
+
subs.add(cb);
|
|
2536
|
+
cb(_val);
|
|
2537
|
+
},
|
|
2538
|
+
unsubscribe: function unsubscribe(cb) {
|
|
2539
|
+
subs["delete"](cb);
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
var isItemsDragDisabled = createStore(true);
|
|
2545
|
+
function getAddedOptions() {
|
|
2546
|
+
var isItemsDragDisabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
2547
|
+
return {
|
|
2548
|
+
dragDisabled: isItemsDragDisabled,
|
|
2549
|
+
zoneItemTabIndex: -1
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
/**
|
|
2554
|
+
* This is an action that wraps around the dndzone action to make it easy to work with drag handles
|
|
2555
|
+
* When using this you must also use the 'dragHandle' action (see below) on an element inside each item within the zone
|
|
2556
|
+
* Credit for the idea and initial implementation goes to @gleuch (Greg Leuch) and @geovie (Georg Vienna)
|
|
2557
|
+
*
|
|
2558
|
+
* @param {HTMLElement} node
|
|
2559
|
+
* @param options - will be passed down to the dndzone
|
|
2560
|
+
* @return {{update: (newOptions: Object) => {}, destroy: () => {}}}
|
|
2561
|
+
*/
|
|
2562
|
+
function dragHandleZone(node, options) {
|
|
2563
|
+
var currentOptions = options;
|
|
2564
|
+
var zone = dndzone$2(node, _objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions()));
|
|
2565
|
+
function isItemDisabledCB(isItemsDragDisabled) {
|
|
2566
|
+
zone.update(_objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions(isItemsDragDisabled)));
|
|
2567
|
+
}
|
|
2568
|
+
isItemsDragDisabled.subscribe(isItemDisabledCB);
|
|
2569
|
+
function consider(e) {
|
|
2570
|
+
var _e$detail$info = e.detail.info,
|
|
2571
|
+
source = _e$detail$info.source,
|
|
2572
|
+
trigger = _e$detail$info.trigger;
|
|
2573
|
+
// Ensure dragging is stopped on drag finish via keyboard
|
|
2574
|
+
if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) {
|
|
2575
|
+
isItemsDragDisabled.set(true);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
function finalize(e) {
|
|
2579
|
+
var source = e.detail.info.source;
|
|
2580
|
+
// Ensure dragging is stopped on drag finish via pointer (mouse, touch)
|
|
2581
|
+
if (source === SOURCES.POINTER) {
|
|
2582
|
+
isItemsDragDisabled.set(true);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
node.addEventListener("consider", consider);
|
|
2586
|
+
node.addEventListener("finalize", finalize);
|
|
2587
|
+
return {
|
|
2588
|
+
update: function update(newOptions) {
|
|
2589
|
+
currentOptions = newOptions;
|
|
2590
|
+
zone.update(_objectSpread2(_objectSpread2({}, currentOptions), getAddedOptions(isItemsDragDisabled.get())));
|
|
2591
|
+
},
|
|
2592
|
+
destroy: function destroy() {
|
|
2593
|
+
node.removeEventListener("consider", consider);
|
|
2594
|
+
node.removeEventListener("finalize", finalize);
|
|
2595
|
+
isItemsDragDisabled.unsubscribe(isItemDisabledCB);
|
|
2596
|
+
}
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* This should be used to mark drag handles inside items that belong to a 'dragHandleZone' (see above)
|
|
2602
|
+
* @param {HTMLElement} handle
|
|
2603
|
+
* @return {{update: *, destroy: *}}
|
|
2604
|
+
*/
|
|
2605
|
+
function dragHandle(handle) {
|
|
2606
|
+
handle.setAttribute("role", "button");
|
|
2607
|
+
function startDrag(e) {
|
|
2608
|
+
// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
|
|
2609
|
+
e.preventDefault();
|
|
2610
|
+
isItemsDragDisabled.set(false);
|
|
2611
|
+
}
|
|
2612
|
+
function handleKeyDown(e) {
|
|
2613
|
+
if (e.key === "Enter" || e.key === " ") isItemsDragDisabled.set(false);
|
|
2614
|
+
}
|
|
2615
|
+
isItemsDragDisabled.subscribe(function (disabled) {
|
|
2616
|
+
handle.tabIndex = disabled ? 0 : -1;
|
|
2617
|
+
handle.style.cursor = disabled ? "grab" : "grabbing";
|
|
2618
|
+
});
|
|
2619
|
+
handle.addEventListener("mousedown", startDrag);
|
|
2620
|
+
handle.addEventListener("touchstart", startDrag);
|
|
2621
|
+
handle.addEventListener("keydown", handleKeyDown);
|
|
2622
|
+
return {
|
|
2623
|
+
update: function update() {},
|
|
2624
|
+
destroy: function destroy() {
|
|
2625
|
+
handle.removeEventListener("mousedown", startDrag);
|
|
2626
|
+
handle.removeEventListener("touchstart", startDrag);
|
|
2627
|
+
handle.removeEventListener("keydown", handleKeyDown);
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
export { DRAGGED_ELEMENT_ID, FEATURE_FLAG_NAMES, SHADOW_ITEM_MARKER_PROPERTY_NAME, SHADOW_PLACEHOLDER_ITEM_ID, SOURCES, TRIGGERS, alertToScreenReader, dndzone$2 as dndzone, dragHandle, dragHandleZone, overrideItemIdKeyNameBeforeInitialisingDndZones, setDebugMode, setFeatureFlag };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-dnd-action",
|
|
3
3
|
"description": "*An awesome drag and drop library for Svelte 3 and 4 (not using the browser's built-in dnd, thanks god): Rich animations, nested containers, touch support and more *",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.46",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/isaacHagoel/svelte-dnd-action.git"
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function createStore(initialValue) {
|
|
2
|
+
let _val = initialValue;
|
|
3
|
+
const subs = new Set();
|
|
4
|
+
return {
|
|
5
|
+
get: () => _val,
|
|
6
|
+
set: newVal => {
|
|
7
|
+
_val = newVal;
|
|
8
|
+
Array.from(subs).forEach(cb => cb(_val));
|
|
9
|
+
},
|
|
10
|
+
subscribe: cb => {
|
|
11
|
+
subs.add(cb);
|
|
12
|
+
cb(_val);
|
|
13
|
+
},
|
|
14
|
+
unsubscribe: cb => {
|
|
15
|
+
subs.delete(cb);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {SOURCES, TRIGGERS} from "../constants";
|
|
2
|
+
import {dndzone} from "../action";
|
|
3
|
+
import {createStore} from "./simpleStore";
|
|
4
|
+
|
|
5
|
+
const isItemsDragDisabled = createStore(true);
|
|
6
|
+
|
|
7
|
+
function getAddedOptions(isItemsDragDisabled = true) {
|
|
8
|
+
return {
|
|
9
|
+
dragDisabled: isItemsDragDisabled,
|
|
10
|
+
zoneItemTabIndex: -1
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This is an action that wraps around the dndzone action to make it easy to work with drag handles
|
|
16
|
+
* When using this you must also use the 'dragHandle' action (see below) on an element inside each item within the zone
|
|
17
|
+
* Credit for the idea and initial implementation goes to @gleuch (Greg Leuch) and @geovie (Georg Vienna)
|
|
18
|
+
*
|
|
19
|
+
* @param {HTMLElement} node
|
|
20
|
+
* @param options - will be passed down to the dndzone
|
|
21
|
+
* @return {{update: (newOptions: Object) => {}, destroy: () => {}}}
|
|
22
|
+
*/
|
|
23
|
+
export function dragHandleZone(node, options) {
|
|
24
|
+
let currentOptions = options;
|
|
25
|
+
const zone = dndzone(node, {
|
|
26
|
+
...currentOptions,
|
|
27
|
+
...getAddedOptions()
|
|
28
|
+
});
|
|
29
|
+
function isItemDisabledCB(isItemsDragDisabled) {
|
|
30
|
+
zone.update({
|
|
31
|
+
...currentOptions,
|
|
32
|
+
...getAddedOptions(isItemsDragDisabled)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
isItemsDragDisabled.subscribe(isItemDisabledCB);
|
|
36
|
+
function consider(e) {
|
|
37
|
+
const {
|
|
38
|
+
info: {source, trigger}
|
|
39
|
+
} = e.detail;
|
|
40
|
+
// Ensure dragging is stopped on drag finish via keyboard
|
|
41
|
+
if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) {
|
|
42
|
+
isItemsDragDisabled.set(true);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function finalize(e) {
|
|
47
|
+
const {
|
|
48
|
+
info: {source}
|
|
49
|
+
} = e.detail;
|
|
50
|
+
// Ensure dragging is stopped on drag finish via pointer (mouse, touch)
|
|
51
|
+
if (source === SOURCES.POINTER) {
|
|
52
|
+
isItemsDragDisabled.set(true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
node.addEventListener("consider", consider);
|
|
57
|
+
node.addEventListener("finalize", finalize);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
update: newOptions => {
|
|
61
|
+
currentOptions = newOptions;
|
|
62
|
+
zone.update({
|
|
63
|
+
...currentOptions,
|
|
64
|
+
...getAddedOptions(isItemsDragDisabled.get())
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
destroy: () => {
|
|
68
|
+
node.removeEventListener("consider", consider);
|
|
69
|
+
node.removeEventListener("finalize", finalize);
|
|
70
|
+
isItemsDragDisabled.unsubscribe(isItemDisabledCB);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* This should be used to mark drag handles inside items that belong to a 'dragHandleZone' (see above)
|
|
77
|
+
* @param {HTMLElement} handle
|
|
78
|
+
* @return {{update: *, destroy: *}}
|
|
79
|
+
*/
|
|
80
|
+
export function dragHandle(handle) {
|
|
81
|
+
handle.setAttribute("role", "button");
|
|
82
|
+
|
|
83
|
+
function startDrag(e) {
|
|
84
|
+
// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
isItemsDragDisabled.set(false);
|
|
87
|
+
}
|
|
88
|
+
function handleKeyDown(e) {
|
|
89
|
+
if (e.key === "Enter" || e.key === " ") isItemsDragDisabled.set(false);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
isItemsDragDisabled.subscribe(disabled => {
|
|
93
|
+
handle.tabIndex = disabled ? 0 : -1;
|
|
94
|
+
handle.style.cursor = disabled ? "grab" : "grabbing";
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
handle.addEventListener("mousedown", startDrag);
|
|
98
|
+
handle.addEventListener("touchstart", startDrag);
|
|
99
|
+
handle.addEventListener("keydown", handleKeyDown);
|
|
100
|
+
return {
|
|
101
|
+
update: () => {},
|
|
102
|
+
destroy: () => {
|
|
103
|
+
handle.removeEventListener("mousedown", startDrag);
|
|
104
|
+
handle.removeEventListener("touchstart", startDrag);
|
|
105
|
+
handle.removeEventListener("keydown", handleKeyDown);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|