@pyreon/dnd 0.11.5 → 0.11.7
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 +1 -0
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +2 -2
- package/package.json +13 -13
- package/src/index.ts +8 -8
- package/src/tests/dnd.test.ts +218 -218
- package/src/types.ts +2 -2
- package/src/use-drag-monitor.ts +3 -3
- package/src/use-draggable.ts +5 -5
- package/src/use-droppable.ts +4 -4
- package/src/use-file-drop.ts +6 -6
- package/src/use-sortable.ts +19 -19
package/src/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export type DragData = Record<string, unknown>
|
|
3
3
|
|
|
4
4
|
/** Position of a drop relative to the target element. */
|
|
5
|
-
export type DropEdge =
|
|
5
|
+
export type DropEdge = 'top' | 'bottom' | 'left' | 'right'
|
|
6
6
|
|
|
7
7
|
/** Drop location information. */
|
|
8
8
|
export interface DropLocation {
|
|
@@ -66,7 +66,7 @@ export interface UseSortableOptions<T> {
|
|
|
66
66
|
/** Called with the reordered items after a drop. */
|
|
67
67
|
onReorder: (items: T[]) => void
|
|
68
68
|
/** Sort axis. Default: "vertical". */
|
|
69
|
-
axis?:
|
|
69
|
+
axis?: 'vertical' | 'horizontal'
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export interface UseSortableResult {
|
package/src/use-drag-monitor.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { monitorForElements } from
|
|
2
|
-
import { onCleanup, signal } from
|
|
3
|
-
import type { DragData } from
|
|
1
|
+
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
2
|
+
import { onCleanup, signal } from '@pyreon/reactivity'
|
|
3
|
+
import type { DragData } from './types'
|
|
4
4
|
|
|
5
5
|
export interface UseDragMonitorOptions {
|
|
6
6
|
/** Called on any drag start in the page. */
|
package/src/use-draggable.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { draggable } from
|
|
2
|
-
import { onCleanup, signal } from
|
|
3
|
-
import type { DragData, UseDraggableOptions, UseDraggableResult } from
|
|
1
|
+
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
2
|
+
import { onCleanup, signal } from '@pyreon/reactivity'
|
|
3
|
+
import type { DragData, UseDraggableOptions, UseDraggableResult } from './types'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Make an element draggable with signal-driven state.
|
|
@@ -32,7 +32,7 @@ export function useDraggable<T extends DragData = DragData>(
|
|
|
32
32
|
if (!el) return
|
|
33
33
|
|
|
34
34
|
const resolveData = () =>
|
|
35
|
-
typeof options.data ===
|
|
35
|
+
typeof options.data === 'function' ? (options.data as () => T)() : options.data
|
|
36
36
|
|
|
37
37
|
const handle = options.handle?.()
|
|
38
38
|
cleanup = draggable({
|
|
@@ -41,7 +41,7 @@ export function useDraggable<T extends DragData = DragData>(
|
|
|
41
41
|
getInitialData: resolveData,
|
|
42
42
|
canDrag: () => {
|
|
43
43
|
const disabled = options.disabled
|
|
44
|
-
if (typeof disabled ===
|
|
44
|
+
if (typeof disabled === 'function') return !disabled()
|
|
45
45
|
return !disabled
|
|
46
46
|
},
|
|
47
47
|
onDragStart: () => {
|
package/src/use-droppable.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { dropTargetForElements } from
|
|
2
|
-
import { onCleanup, signal } from
|
|
3
|
-
import type { DragData, UseDroppableOptions, UseDroppableResult } from
|
|
1
|
+
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
2
|
+
import { onCleanup, signal } from '@pyreon/reactivity'
|
|
3
|
+
import type { DragData, UseDroppableOptions, UseDroppableResult } from './types'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Make an element a drop target with signal-driven state.
|
|
@@ -36,7 +36,7 @@ export function useDroppable<T extends DragData = DragData>(
|
|
|
36
36
|
element: el,
|
|
37
37
|
getData: () => {
|
|
38
38
|
if (!options.data) return {}
|
|
39
|
-
return typeof options.data ===
|
|
39
|
+
return typeof options.data === 'function' ? (options.data as () => T)() : options.data
|
|
40
40
|
},
|
|
41
41
|
canDrop: ({ source }) => {
|
|
42
42
|
if (!options.canDrop) return true
|
package/src/use-file-drop.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dropTargetForExternal,
|
|
3
3
|
monitorForExternal,
|
|
4
|
-
} from
|
|
5
|
-
import { containsFiles, getFiles } from
|
|
6
|
-
import { onCleanup, signal } from
|
|
4
|
+
} from '@atlaskit/pragmatic-drag-and-drop/external/adapter'
|
|
5
|
+
import { containsFiles, getFiles } from '@atlaskit/pragmatic-drag-and-drop/external/file'
|
|
6
|
+
import { onCleanup, signal } from '@pyreon/reactivity'
|
|
7
7
|
|
|
8
8
|
export interface UseFileDropOptions {
|
|
9
9
|
/** Element getter for the drop zone. */
|
|
@@ -55,10 +55,10 @@ export function useFileDrop(options: UseFileDropOptions): UseFileDropResult {
|
|
|
55
55
|
|
|
56
56
|
function matchesAccept(file: File, accept: string[]): boolean {
|
|
57
57
|
return accept.some((pattern) => {
|
|
58
|
-
if (pattern.startsWith(
|
|
58
|
+
if (pattern.startsWith('.')) {
|
|
59
59
|
return file.name.toLowerCase().endsWith(pattern.toLowerCase())
|
|
60
60
|
}
|
|
61
|
-
if (pattern.endsWith(
|
|
61
|
+
if (pattern.endsWith('/*')) {
|
|
62
62
|
return file.type.startsWith(pattern.slice(0, -1))
|
|
63
63
|
}
|
|
64
64
|
return file.type === pattern
|
|
@@ -88,7 +88,7 @@ export function useFileDrop(options: UseFileDropOptions): UseFileDropResult {
|
|
|
88
88
|
element: el,
|
|
89
89
|
canDrop: ({ source }) => {
|
|
90
90
|
const disabled = options.disabled
|
|
91
|
-
if (typeof disabled ===
|
|
91
|
+
if (typeof disabled === 'function' ? disabled() : disabled) return false
|
|
92
92
|
return containsFiles({ source })
|
|
93
93
|
},
|
|
94
94
|
onDragEnter: () => isOver.set(true),
|
package/src/use-sortable.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { combine } from
|
|
2
|
-
import { draggable, dropTargetForElements } from
|
|
3
|
-
import { autoScrollForElements } from
|
|
1
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'
|
|
2
|
+
import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
3
|
+
import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element'
|
|
4
4
|
import {
|
|
5
5
|
attachClosestEdge,
|
|
6
6
|
type Edge,
|
|
7
7
|
extractClosestEdge,
|
|
8
|
-
} from
|
|
9
|
-
import { onCleanup, signal } from
|
|
10
|
-
import type { DropEdge, UseSortableOptions, UseSortableResult } from
|
|
8
|
+
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge'
|
|
9
|
+
import { onCleanup, signal } from '@pyreon/reactivity'
|
|
10
|
+
import type { DropEdge, UseSortableOptions, UseSortableResult } from './types'
|
|
11
11
|
|
|
12
|
-
const SORT_KEY =
|
|
13
|
-
const SORT_ID =
|
|
12
|
+
const SORT_KEY = '__pyreon_sortable_key'
|
|
13
|
+
const SORT_ID = '__pyreon_sortable_id'
|
|
14
14
|
|
|
15
15
|
let _sortableCounter = 0
|
|
16
16
|
|
|
@@ -58,7 +58,7 @@ export function useSortable<T>(options: UseSortableOptions<T>): UseSortableResul
|
|
|
58
58
|
const activeId = signal<string | number | null>(null)
|
|
59
59
|
const overId = signal<string | number | null>(null)
|
|
60
60
|
const overEdge = signal<DropEdge | null>(null)
|
|
61
|
-
const axis = options.axis ??
|
|
61
|
+
const axis = options.axis ?? 'vertical'
|
|
62
62
|
|
|
63
63
|
const cleanups: (() => void)[] = []
|
|
64
64
|
|
|
@@ -80,7 +80,7 @@ export function useSortable<T>(options: UseSortableOptions<T>): UseSortableResul
|
|
|
80
80
|
|
|
81
81
|
// Determine insert position based on closest edge
|
|
82
82
|
const rawInsert =
|
|
83
|
-
edge ===
|
|
83
|
+
edge === 'bottom' || edge === 'right'
|
|
84
84
|
? dropIndex >= dragIndex
|
|
85
85
|
? dropIndex
|
|
86
86
|
: dropIndex + 1
|
|
@@ -121,8 +121,8 @@ export function useSortable<T>(options: UseSortableOptions<T>): UseSortableResul
|
|
|
121
121
|
const keyHandler = (e: KeyboardEvent) => {
|
|
122
122
|
if (!e.altKey) return
|
|
123
123
|
|
|
124
|
-
const isUp = axis ===
|
|
125
|
-
const isDown = axis ===
|
|
124
|
+
const isUp = axis === 'vertical' ? e.key === 'ArrowUp' : e.key === 'ArrowLeft'
|
|
125
|
+
const isDown = axis === 'vertical' ? e.key === 'ArrowDown' : e.key === 'ArrowRight'
|
|
126
126
|
if (!isUp && !isDown) return
|
|
127
127
|
|
|
128
128
|
const focused = document.activeElement as HTMLElement | null
|
|
@@ -148,7 +148,7 @@ export function useSortable<T>(options: UseSortableOptions<T>): UseSortableResul
|
|
|
148
148
|
|
|
149
149
|
// Restore focus after DOM update
|
|
150
150
|
requestAnimationFrame(() => {
|
|
151
|
-
const items = el.querySelectorAll(
|
|
151
|
+
const items = el.querySelectorAll('[data-pyreon-sort-key]')
|
|
152
152
|
for (const item of items) {
|
|
153
153
|
if ((item as HTMLElement).dataset.pyreonSortKey === focusedKey) {
|
|
154
154
|
;(item as HTMLElement).focus()
|
|
@@ -158,18 +158,18 @@ export function useSortable<T>(options: UseSortableOptions<T>): UseSortableResul
|
|
|
158
158
|
})
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
el.addEventListener(
|
|
162
|
-
cleanups.push(() => el.removeEventListener(
|
|
161
|
+
el.addEventListener('keydown', keyHandler)
|
|
162
|
+
cleanups.push(() => el.removeEventListener('keydown', keyHandler))
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
function itemRef(key: string | number): (el: HTMLElement) => void {
|
|
166
166
|
return (el: HTMLElement) => {
|
|
167
167
|
el.dataset.pyreonSortKey = String(key)
|
|
168
|
-
if (!el.hasAttribute(
|
|
169
|
-
el.setAttribute(
|
|
170
|
-
el.setAttribute(
|
|
168
|
+
if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '0')
|
|
169
|
+
el.setAttribute('role', 'listitem')
|
|
170
|
+
el.setAttribute('aria-roledescription', 'sortable item')
|
|
171
171
|
|
|
172
|
-
const allowedEdges: Edge[] = axis ===
|
|
172
|
+
const allowedEdges: Edge[] = axis === 'vertical' ? ['top', 'bottom'] : ['left', 'right']
|
|
173
173
|
|
|
174
174
|
const cleanup = combine(
|
|
175
175
|
draggable({
|