@dnd-kit/react 0.0.1

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 ADDED
@@ -0,0 +1,17 @@
1
+ # @dnd-kit/react
2
+
3
+ [![Stable release](https://img.shields.io/npm/v/@dnd-kit/react.svg)](https://npm.im/@dnd-kit/react)
4
+
5
+ The React layer for @dnd-kit, built on top of @dnd-kit/dom.
6
+
7
+ ## Installation
8
+
9
+ To get started, install the `@dnd-kit/react` package via npm or yarn:
10
+
11
+ ```
12
+ npm install @dnd-kit/react
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Visit [docs.dndkit.com](https://docs.dndkit.com) to learn how to get started with @dnd-kit.
package/hooks.cjs ADDED
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var state = require('@dnd-kit/state');
5
+ var reactDom = require('react-dom');
6
+
7
+ // src/hooks/useConstant.ts
8
+ function useConstant(initializer, dependency) {
9
+ const ref = react.useRef();
10
+ const previousDependency = react.useRef(dependency);
11
+ if (!ref.current) {
12
+ ref.current = initializer();
13
+ }
14
+ if (previousDependency.current !== dependency) {
15
+ previousDependency.current = dependency;
16
+ ref.current = initializer();
17
+ }
18
+ return ref.current;
19
+ }
20
+ var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
21
+ var useIsomorphicLayoutEffect = canUseDOM ? react.useLayoutEffect : react.useEffect;
22
+
23
+ // src/hooks/useSignal.ts
24
+ function useSignal(signalOrValue, sync = false) {
25
+ const sig = useConstant(
26
+ () => signalOrValue instanceof state.Signal ? signalOrValue : state.signal(signalOrValue)
27
+ );
28
+ let val = sig.peek();
29
+ const update = react.useState(val)[1];
30
+ useIsomorphicLayoutEffect(
31
+ () => state.effect(() => {
32
+ if (val !== (val = sig.value)) {
33
+ if (sync) {
34
+ reactDom.flushSync(() => update(val));
35
+ } else {
36
+ update(val);
37
+ }
38
+ }
39
+ }),
40
+ [sync]
41
+ );
42
+ return sig;
43
+ }
44
+
45
+ // src/hooks/useComputed.ts
46
+ function useComputed(compute, sync = false) {
47
+ return useSignal(
48
+ useConstant(() => state.computed(compute)),
49
+ sync
50
+ );
51
+ }
52
+ function useLatest(value) {
53
+ const valueRef = react.useRef(value);
54
+ useIsomorphicLayoutEffect(() => {
55
+ valueRef.current = value;
56
+ }, [value]);
57
+ return valueRef;
58
+ }
59
+
60
+ // src/hooks/useEvent.ts
61
+ function useEvent(handler) {
62
+ const handlerRef = useLatest(handler);
63
+ return react.useCallback(
64
+ function(...args) {
65
+ return handlerRef.current?.(...args);
66
+ },
67
+ [handlerRef]
68
+ );
69
+ }
70
+
71
+ // src/hooks/useImmediateEffect.ts
72
+ function useImmediateEffect(callback, _) {
73
+ callback();
74
+ }
75
+ function useOnValueChange(value, onChange, effect3 = react.useEffect, compare = Object.is) {
76
+ const tracked = react.useRef(value);
77
+ effect3(() => {
78
+ const oldValue = tracked.current;
79
+ if (!compare(value, tracked.current)) {
80
+ tracked.current = value;
81
+ onChange(value, oldValue);
82
+ }
83
+ }, [onChange, value]);
84
+ }
85
+ function useSignalEffect(compute, deps = []) {
86
+ react.useEffect(() => state.effect(compute), deps);
87
+ }
88
+
89
+ exports.useComputed = useComputed;
90
+ exports.useConstant = useConstant;
91
+ exports.useEvent = useEvent;
92
+ exports.useImmediateEffect = useImmediateEffect;
93
+ exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
94
+ exports.useLatest = useLatest;
95
+ exports.useOnValueChange = useOnValueChange;
96
+ exports.useSignalEffect = useSignalEffect;
97
+ //# sourceMappingURL=out.js.map
98
+ //# sourceMappingURL=hooks.cjs.map
package/hooks.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import * as _preact_signals_core from '@preact/signals-core';
2
+ import * as react from 'react';
3
+ import { EffectCallback, DependencyList, useLayoutEffect, useEffect } from 'react';
4
+
5
+ declare function useConstant<T = any>(initializer: () => T, dependency?: any): T;
6
+
7
+ declare function useComputed<T = any>(compute: () => T, sync?: boolean): _preact_signals_core.ReadonlySignal<T>;
8
+
9
+ declare function useEvent<T extends Function>(handler: T | undefined): (...args: any) => any;
10
+
11
+ declare function useImmediateEffect(callback: EffectCallback, _?: DependencyList): void;
12
+
13
+ /**
14
+ * A hook that resolves to useEffect on the server and useLayoutEffect on the client
15
+ * @param callback {function} Callback function that is invoked when the dependencies of the hook change
16
+ */
17
+ declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
18
+
19
+ declare function useLatest<T>(value: T): react.MutableRefObject<T | undefined>;
20
+
21
+ declare function useOnValueChange<T>(value: T, onChange: (value: T, oldValue: T) => void, effect?: typeof useEffect, compare?: (value1: any, value2: any) => boolean): void;
22
+
23
+ declare function useSignalEffect(compute: () => void, deps?: any[]): void;
24
+
25
+ export { useComputed, useConstant, useEvent, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnValueChange, useSignalEffect };
package/hooks.js ADDED
@@ -0,0 +1,89 @@
1
+ import { useRef, useLayoutEffect, useEffect, useCallback, useState } from 'react';
2
+ import { computed, effect, Signal, signal } from '@dnd-kit/state';
3
+ import { flushSync } from 'react-dom';
4
+
5
+ // src/hooks/useConstant.ts
6
+ function useConstant(initializer, dependency) {
7
+ const ref = useRef();
8
+ const previousDependency = useRef(dependency);
9
+ if (!ref.current) {
10
+ ref.current = initializer();
11
+ }
12
+ if (previousDependency.current !== dependency) {
13
+ previousDependency.current = dependency;
14
+ ref.current = initializer();
15
+ }
16
+ return ref.current;
17
+ }
18
+ var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
19
+ var useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
20
+
21
+ // src/hooks/useSignal.ts
22
+ function useSignal(signalOrValue, sync = false) {
23
+ const sig = useConstant(
24
+ () => signalOrValue instanceof Signal ? signalOrValue : signal(signalOrValue)
25
+ );
26
+ let val = sig.peek();
27
+ const update = useState(val)[1];
28
+ useIsomorphicLayoutEffect(
29
+ () => effect(() => {
30
+ if (val !== (val = sig.value)) {
31
+ if (sync) {
32
+ flushSync(() => update(val));
33
+ } else {
34
+ update(val);
35
+ }
36
+ }
37
+ }),
38
+ [sync]
39
+ );
40
+ return sig;
41
+ }
42
+
43
+ // src/hooks/useComputed.ts
44
+ function useComputed(compute, sync = false) {
45
+ return useSignal(
46
+ useConstant(() => computed(compute)),
47
+ sync
48
+ );
49
+ }
50
+ function useLatest(value) {
51
+ const valueRef = useRef(value);
52
+ useIsomorphicLayoutEffect(() => {
53
+ valueRef.current = value;
54
+ }, [value]);
55
+ return valueRef;
56
+ }
57
+
58
+ // src/hooks/useEvent.ts
59
+ function useEvent(handler) {
60
+ const handlerRef = useLatest(handler);
61
+ return useCallback(
62
+ function(...args) {
63
+ return handlerRef.current?.(...args);
64
+ },
65
+ [handlerRef]
66
+ );
67
+ }
68
+
69
+ // src/hooks/useImmediateEffect.ts
70
+ function useImmediateEffect(callback, _) {
71
+ callback();
72
+ }
73
+ function useOnValueChange(value, onChange, effect3 = useEffect, compare = Object.is) {
74
+ const tracked = useRef(value);
75
+ effect3(() => {
76
+ const oldValue = tracked.current;
77
+ if (!compare(value, tracked.current)) {
78
+ tracked.current = value;
79
+ onChange(value, oldValue);
80
+ }
81
+ }, [onChange, value]);
82
+ }
83
+ function useSignalEffect(compute, deps = []) {
84
+ useEffect(() => effect(compute), deps);
85
+ }
86
+
87
+ export { useComputed, useConstant, useEvent, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnValueChange, useSignalEffect };
88
+ //# sourceMappingURL=out.js.map
89
+ //# sourceMappingURL=hooks.js.map
package/index.cjs ADDED
@@ -0,0 +1,252 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var dom = require('@dnd-kit/dom');
5
+ var state = require('@dnd-kit/state');
6
+ var reactDom = require('react-dom');
7
+ var hooks = require('@dnd-kit/react/hooks');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+ var utilities = require('@dnd-kit/react/utilities');
10
+
11
+ // src/core/context/hooks.ts
12
+ var DragDropContext = react.createContext(
13
+ new dom.DragDropManager()
14
+ );
15
+ function useConstant(initializer, dependency) {
16
+ const ref = react.useRef();
17
+ const previousDependency = react.useRef(dependency);
18
+ if (!ref.current) {
19
+ ref.current = initializer();
20
+ }
21
+ if (previousDependency.current !== dependency) {
22
+ previousDependency.current = dependency;
23
+ ref.current = initializer();
24
+ }
25
+ return ref.current;
26
+ }
27
+ var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
28
+ var useIsomorphicLayoutEffect = canUseDOM ? react.useLayoutEffect : react.useEffect;
29
+
30
+ // src/hooks/useSignal.ts
31
+ function useSignal(signalOrValue, sync = false) {
32
+ const sig = useConstant(
33
+ () => signalOrValue instanceof state.Signal ? signalOrValue : state.signal(signalOrValue)
34
+ );
35
+ let val = sig.peek();
36
+ const update = react.useState(val)[1];
37
+ useIsomorphicLayoutEffect(
38
+ () => state.effect(() => {
39
+ if (val !== (val = sig.value)) {
40
+ if (sync) {
41
+ reactDom.flushSync(() => update(val));
42
+ } else {
43
+ update(val);
44
+ }
45
+ }
46
+ }),
47
+ [sync]
48
+ );
49
+ return sig;
50
+ }
51
+
52
+ // src/hooks/useComputed.ts
53
+ function useComputed(compute, sync = false) {
54
+ return useSignal(
55
+ useConstant(() => state.computed(compute)),
56
+ sync
57
+ );
58
+ }
59
+
60
+ // src/core/context/hooks.ts
61
+ function useDragDropManager() {
62
+ return react.useContext(DragDropContext);
63
+ }
64
+ function useDragOperation() {
65
+ const manager = useDragDropManager();
66
+ const { dragOperation } = manager;
67
+ const source = useComputed(() => dragOperation.source);
68
+ const target = useComputed(() => dragOperation.target);
69
+ return {
70
+ get source() {
71
+ return source.value;
72
+ },
73
+ get target() {
74
+ return target.value;
75
+ }
76
+ };
77
+ }
78
+ function useRenderer() {
79
+ const [_, startTransition] = react.useTransition();
80
+ const [transitionCount, setTransitionCount] = react.useState(0);
81
+ const rendering = react.useRef();
82
+ const resolver = react.useRef();
83
+ const renderer = hooks.useConstant(() => ({
84
+ get rendering() {
85
+ return rendering.current ?? Promise.resolve();
86
+ }
87
+ }));
88
+ hooks.useOnValueChange(transitionCount, () => {
89
+ resolver.current?.();
90
+ rendering.current = void 0;
91
+ });
92
+ return {
93
+ renderer,
94
+ trackRendering(callback) {
95
+ if (!rendering.current) {
96
+ rendering.current = new Promise((resolve) => {
97
+ resolver.current = resolve;
98
+ });
99
+ }
100
+ startTransition(() => {
101
+ callback();
102
+ setTransitionCount((count) => count + 1);
103
+ });
104
+ }
105
+ };
106
+ }
107
+ var DragDropProvider = react.forwardRef(
108
+ function DragDropProvider2({
109
+ children,
110
+ onCollision,
111
+ onBeforeDragStart,
112
+ onDragStart,
113
+ onDragMove,
114
+ onDragOver,
115
+ onDragEnd,
116
+ ...input
117
+ }, ref) {
118
+ const { renderer, trackRendering } = useRenderer();
119
+ const manager = hooks.useConstant(() => {
120
+ const instance = input.manager ?? new dom.DragDropManager(input);
121
+ instance.renderer = renderer;
122
+ return instance;
123
+ });
124
+ const { plugins, modifiers } = input;
125
+ const handleBeforeDragStart = hooks.useLatest(onBeforeDragStart);
126
+ const handleDragStart = hooks.useEvent(onDragStart);
127
+ const handleDragOver = hooks.useLatest(onDragOver);
128
+ const handleDragMove = hooks.useLatest(onDragMove);
129
+ const handleDragEnd = hooks.useLatest(onDragEnd);
130
+ const handleCollision = hooks.useEvent(onCollision);
131
+ react.useEffect(() => {
132
+ manager.monitor.addEventListener("beforedragstart", (event, manager2) => {
133
+ const callback = handleBeforeDragStart.current;
134
+ if (callback) {
135
+ trackRendering(() => callback(event, manager2));
136
+ }
137
+ });
138
+ manager.monitor.addEventListener("dragstart", handleDragStart);
139
+ manager.monitor.addEventListener("dragover", (event, manager2) => {
140
+ const callback = handleDragOver.current;
141
+ if (callback) {
142
+ trackRendering(() => callback(event, manager2));
143
+ }
144
+ });
145
+ manager.monitor.addEventListener("dragmove", (event, manager2) => {
146
+ const callback = handleDragMove.current;
147
+ if (callback) {
148
+ trackRendering(() => callback(event, manager2));
149
+ }
150
+ });
151
+ manager.monitor.addEventListener("dragend", (event, manager2) => {
152
+ const callback = handleDragEnd.current;
153
+ if (callback) {
154
+ trackRendering(() => callback(event, manager2));
155
+ }
156
+ });
157
+ manager.monitor.addEventListener("collision", handleCollision);
158
+ return () => {
159
+ manager.destroy();
160
+ };
161
+ }, [manager]);
162
+ hooks.useOnValueChange(
163
+ plugins,
164
+ () => manager.plugins = plugins ?? dom.defaultPreset.plugins
165
+ );
166
+ hooks.useOnValueChange(modifiers, () => manager.modifiers = modifiers ?? []);
167
+ react.useImperativeHandle(ref, () => manager, [manager]);
168
+ return /* @__PURE__ */ jsxRuntime.jsx(DragDropContext.Provider, { value: manager, children });
169
+ }
170
+ );
171
+ function useDraggable(input) {
172
+ const { disabled, id, sensors } = input;
173
+ const manager = useDragDropManager();
174
+ const handle = utilities.getCurrentValue(input.handle);
175
+ const element = utilities.getCurrentValue(input.element);
176
+ const draggable = hooks.useConstant(
177
+ () => new dom.Draggable({ ...input, handle, element }, manager),
178
+ manager
179
+ );
180
+ const isDragSource = hooks.useComputed(() => draggable.isDragSource);
181
+ hooks.useOnValueChange(id, () => draggable.id = id);
182
+ hooks.useOnValueChange(handle, () => draggable.handle = handle);
183
+ hooks.useOnValueChange(element, () => draggable.element = element);
184
+ hooks.useOnValueChange(disabled, () => draggable.disabled = disabled === true);
185
+ hooks.useOnValueChange(sensors, () => draggable.sensors = sensors);
186
+ hooks.useOnValueChange(
187
+ input.feedback,
188
+ () => draggable.feedback = input.feedback ?? "default"
189
+ );
190
+ react.useEffect(() => {
191
+ return draggable.destroy;
192
+ }, [draggable]);
193
+ return {
194
+ get isDragSource() {
195
+ return isDragSource.value;
196
+ },
197
+ handleRef: react.useCallback(
198
+ (element2) => {
199
+ draggable.handle = element2 ?? void 0;
200
+ },
201
+ [draggable]
202
+ ),
203
+ ref: react.useCallback(
204
+ (element2) => {
205
+ draggable.element = element2 ?? void 0;
206
+ },
207
+ [draggable]
208
+ )
209
+ };
210
+ }
211
+ function useDroppable(input) {
212
+ const manager = useDragDropManager();
213
+ const { collisionDetector, disabled, id, accept, type } = input;
214
+ const element = utilities.getCurrentValue(input.element);
215
+ const droppable = hooks.useConstant(
216
+ () => new dom.Droppable({ ...input, element }, manager),
217
+ manager
218
+ );
219
+ const isDisabled = hooks.useComputed(() => droppable.disabled);
220
+ const isDropTarget = hooks.useComputed(() => droppable.isDropTarget);
221
+ hooks.useOnValueChange(id, () => droppable.id = id);
222
+ hooks.useOnValueChange(accept, () => droppable.id = id, void 0, state.deepEqual);
223
+ hooks.useOnValueChange(collisionDetector, () => droppable.id = id);
224
+ hooks.useOnValueChange(disabled, () => droppable.disabled = disabled === true);
225
+ hooks.useOnValueChange(element, () => droppable.element = element);
226
+ hooks.useOnValueChange(type, () => droppable.id = id);
227
+ react.useEffect(() => {
228
+ return droppable.destroy;
229
+ }, [droppable]);
230
+ return {
231
+ get isDisabled() {
232
+ return isDisabled.value;
233
+ },
234
+ get isDropTarget() {
235
+ return isDropTarget.value;
236
+ },
237
+ ref: react.useCallback(
238
+ (element2) => {
239
+ droppable.element = element2 ?? void 0;
240
+ },
241
+ [droppable]
242
+ )
243
+ };
244
+ }
245
+
246
+ exports.DragDropProvider = DragDropProvider;
247
+ exports.useDragDropManager = useDragDropManager;
248
+ exports.useDragOperation = useDragOperation;
249
+ exports.useDraggable = useDraggable;
250
+ exports.useDroppable = useDroppable;
251
+ //# sourceMappingURL=out.js.map
252
+ //# sourceMappingURL=index.cjs.map
package/index.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import * as _dnd_kit_dom from '@dnd-kit/dom';
2
+ import { DragDropManager, Draggable, Droppable, DragDropManagerInput, DraggableInput, DroppableInput } from '@dnd-kit/dom';
3
+ import * as _dnd_kit_abstract from '@dnd-kit/abstract';
4
+ import { DragDropEvents, Data } from '@dnd-kit/abstract';
5
+ import * as react from 'react';
6
+ import { PropsWithChildren } from 'react';
7
+ import { RefOrValue } from '@dnd-kit/react/utilities';
8
+
9
+ declare function useDragDropManager(): _dnd_kit_dom.DragDropManager<_dnd_kit_dom.Draggable<_dnd_kit_abstract.Data>, _dnd_kit_dom.Droppable<_dnd_kit_abstract.Data>>;
10
+ declare function useDragOperation(): {
11
+ readonly source: _dnd_kit_dom.Draggable<_dnd_kit_abstract.Data> | null;
12
+ readonly target: _dnd_kit_dom.Droppable<_dnd_kit_abstract.Data> | null;
13
+ };
14
+
15
+ type Events = DragDropEvents<Draggable, Droppable, DragDropManager>;
16
+ interface Props extends DragDropManagerInput, PropsWithChildren {
17
+ manager?: DragDropManager;
18
+ onBeforeDragStart?: Events['beforedragstart'];
19
+ onCollision?: Events['collision'];
20
+ onDragStart?: Events['dragstart'];
21
+ onDragMove?: Events['dragmove'];
22
+ onDragOver?: Events['dragover'];
23
+ onDragEnd?: Events['dragend'];
24
+ }
25
+ declare const DragDropProvider: react.ForwardRefExoticComponent<Props & react.RefAttributes<DragDropManager<Draggable<_dnd_kit_abstract.Data>, Droppable<_dnd_kit_abstract.Data>>>>;
26
+
27
+ interface UseDraggableInput<T extends Data = Data> extends Omit<DraggableInput<T>, 'handle' | 'element'> {
28
+ handle?: RefOrValue<Element>;
29
+ element?: RefOrValue<Element>;
30
+ }
31
+ declare function useDraggable<T extends Data = Data>(input: UseDraggableInput<T>): {
32
+ readonly isDragSource: boolean;
33
+ handleRef: (element: Element | null) => void;
34
+ ref: (element: Element | null) => void;
35
+ };
36
+
37
+ interface UseDroppableInput<T extends Data = Data> extends Omit<DroppableInput<T>, 'element'> {
38
+ element?: RefOrValue<Element>;
39
+ }
40
+ declare function useDroppable<T extends Data = Data>(input: UseDroppableInput<T>): {
41
+ readonly isDisabled: boolean;
42
+ readonly isDropTarget: boolean;
43
+ ref: (element: Element | null) => void;
44
+ };
45
+
46
+ export { DragDropProvider, useDragDropManager, useDragOperation, useDraggable, useDroppable };
package/index.js ADDED
@@ -0,0 +1,246 @@
1
+ import { createContext, forwardRef, useEffect, useImperativeHandle, useContext, useTransition, useState, useRef, useCallback, useLayoutEffect } from 'react';
2
+ import { DragDropManager, defaultPreset, Draggable, Droppable } from '@dnd-kit/dom';
3
+ import { deepEqual, Signal, signal, effect, computed } from '@dnd-kit/state';
4
+ import { flushSync } from 'react-dom';
5
+ import { useConstant as useConstant$1, useLatest, useEvent, useOnValueChange, useComputed as useComputed$1 } from '@dnd-kit/react/hooks';
6
+ import { jsx } from 'react/jsx-runtime';
7
+ import { getCurrentValue } from '@dnd-kit/react/utilities';
8
+
9
+ // src/core/context/hooks.ts
10
+ var DragDropContext = createContext(
11
+ new DragDropManager()
12
+ );
13
+ function useConstant(initializer, dependency) {
14
+ const ref = useRef();
15
+ const previousDependency = useRef(dependency);
16
+ if (!ref.current) {
17
+ ref.current = initializer();
18
+ }
19
+ if (previousDependency.current !== dependency) {
20
+ previousDependency.current = dependency;
21
+ ref.current = initializer();
22
+ }
23
+ return ref.current;
24
+ }
25
+ var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
26
+ var useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
27
+
28
+ // src/hooks/useSignal.ts
29
+ function useSignal(signalOrValue, sync = false) {
30
+ const sig = useConstant(
31
+ () => signalOrValue instanceof Signal ? signalOrValue : signal(signalOrValue)
32
+ );
33
+ let val = sig.peek();
34
+ const update = useState(val)[1];
35
+ useIsomorphicLayoutEffect(
36
+ () => effect(() => {
37
+ if (val !== (val = sig.value)) {
38
+ if (sync) {
39
+ flushSync(() => update(val));
40
+ } else {
41
+ update(val);
42
+ }
43
+ }
44
+ }),
45
+ [sync]
46
+ );
47
+ return sig;
48
+ }
49
+
50
+ // src/hooks/useComputed.ts
51
+ function useComputed(compute, sync = false) {
52
+ return useSignal(
53
+ useConstant(() => computed(compute)),
54
+ sync
55
+ );
56
+ }
57
+
58
+ // src/core/context/hooks.ts
59
+ function useDragDropManager() {
60
+ return useContext(DragDropContext);
61
+ }
62
+ function useDragOperation() {
63
+ const manager = useDragDropManager();
64
+ const { dragOperation } = manager;
65
+ const source = useComputed(() => dragOperation.source);
66
+ const target = useComputed(() => dragOperation.target);
67
+ return {
68
+ get source() {
69
+ return source.value;
70
+ },
71
+ get target() {
72
+ return target.value;
73
+ }
74
+ };
75
+ }
76
+ function useRenderer() {
77
+ const [_, startTransition] = useTransition();
78
+ const [transitionCount, setTransitionCount] = useState(0);
79
+ const rendering = useRef();
80
+ const resolver = useRef();
81
+ const renderer = useConstant$1(() => ({
82
+ get rendering() {
83
+ return rendering.current ?? Promise.resolve();
84
+ }
85
+ }));
86
+ useOnValueChange(transitionCount, () => {
87
+ resolver.current?.();
88
+ rendering.current = void 0;
89
+ });
90
+ return {
91
+ renderer,
92
+ trackRendering(callback) {
93
+ if (!rendering.current) {
94
+ rendering.current = new Promise((resolve) => {
95
+ resolver.current = resolve;
96
+ });
97
+ }
98
+ startTransition(() => {
99
+ callback();
100
+ setTransitionCount((count) => count + 1);
101
+ });
102
+ }
103
+ };
104
+ }
105
+ var DragDropProvider = forwardRef(
106
+ function DragDropProvider2({
107
+ children,
108
+ onCollision,
109
+ onBeforeDragStart,
110
+ onDragStart,
111
+ onDragMove,
112
+ onDragOver,
113
+ onDragEnd,
114
+ ...input
115
+ }, ref) {
116
+ const { renderer, trackRendering } = useRenderer();
117
+ const manager = useConstant$1(() => {
118
+ const instance = input.manager ?? new DragDropManager(input);
119
+ instance.renderer = renderer;
120
+ return instance;
121
+ });
122
+ const { plugins, modifiers } = input;
123
+ const handleBeforeDragStart = useLatest(onBeforeDragStart);
124
+ const handleDragStart = useEvent(onDragStart);
125
+ const handleDragOver = useLatest(onDragOver);
126
+ const handleDragMove = useLatest(onDragMove);
127
+ const handleDragEnd = useLatest(onDragEnd);
128
+ const handleCollision = useEvent(onCollision);
129
+ useEffect(() => {
130
+ manager.monitor.addEventListener("beforedragstart", (event, manager2) => {
131
+ const callback = handleBeforeDragStart.current;
132
+ if (callback) {
133
+ trackRendering(() => callback(event, manager2));
134
+ }
135
+ });
136
+ manager.monitor.addEventListener("dragstart", handleDragStart);
137
+ manager.monitor.addEventListener("dragover", (event, manager2) => {
138
+ const callback = handleDragOver.current;
139
+ if (callback) {
140
+ trackRendering(() => callback(event, manager2));
141
+ }
142
+ });
143
+ manager.monitor.addEventListener("dragmove", (event, manager2) => {
144
+ const callback = handleDragMove.current;
145
+ if (callback) {
146
+ trackRendering(() => callback(event, manager2));
147
+ }
148
+ });
149
+ manager.monitor.addEventListener("dragend", (event, manager2) => {
150
+ const callback = handleDragEnd.current;
151
+ if (callback) {
152
+ trackRendering(() => callback(event, manager2));
153
+ }
154
+ });
155
+ manager.monitor.addEventListener("collision", handleCollision);
156
+ return () => {
157
+ manager.destroy();
158
+ };
159
+ }, [manager]);
160
+ useOnValueChange(
161
+ plugins,
162
+ () => manager.plugins = plugins ?? defaultPreset.plugins
163
+ );
164
+ useOnValueChange(modifiers, () => manager.modifiers = modifiers ?? []);
165
+ useImperativeHandle(ref, () => manager, [manager]);
166
+ return /* @__PURE__ */ jsx(DragDropContext.Provider, { value: manager, children });
167
+ }
168
+ );
169
+ function useDraggable(input) {
170
+ const { disabled, id, sensors } = input;
171
+ const manager = useDragDropManager();
172
+ const handle = getCurrentValue(input.handle);
173
+ const element = getCurrentValue(input.element);
174
+ const draggable = useConstant$1(
175
+ () => new Draggable({ ...input, handle, element }, manager),
176
+ manager
177
+ );
178
+ const isDragSource = useComputed$1(() => draggable.isDragSource);
179
+ useOnValueChange(id, () => draggable.id = id);
180
+ useOnValueChange(handle, () => draggable.handle = handle);
181
+ useOnValueChange(element, () => draggable.element = element);
182
+ useOnValueChange(disabled, () => draggable.disabled = disabled === true);
183
+ useOnValueChange(sensors, () => draggable.sensors = sensors);
184
+ useOnValueChange(
185
+ input.feedback,
186
+ () => draggable.feedback = input.feedback ?? "default"
187
+ );
188
+ useEffect(() => {
189
+ return draggable.destroy;
190
+ }, [draggable]);
191
+ return {
192
+ get isDragSource() {
193
+ return isDragSource.value;
194
+ },
195
+ handleRef: useCallback(
196
+ (element2) => {
197
+ draggable.handle = element2 ?? void 0;
198
+ },
199
+ [draggable]
200
+ ),
201
+ ref: useCallback(
202
+ (element2) => {
203
+ draggable.element = element2 ?? void 0;
204
+ },
205
+ [draggable]
206
+ )
207
+ };
208
+ }
209
+ function useDroppable(input) {
210
+ const manager = useDragDropManager();
211
+ const { collisionDetector, disabled, id, accept, type } = input;
212
+ const element = getCurrentValue(input.element);
213
+ const droppable = useConstant$1(
214
+ () => new Droppable({ ...input, element }, manager),
215
+ manager
216
+ );
217
+ const isDisabled = useComputed$1(() => droppable.disabled);
218
+ const isDropTarget = useComputed$1(() => droppable.isDropTarget);
219
+ useOnValueChange(id, () => droppable.id = id);
220
+ useOnValueChange(accept, () => droppable.id = id, void 0, deepEqual);
221
+ useOnValueChange(collisionDetector, () => droppable.id = id);
222
+ useOnValueChange(disabled, () => droppable.disabled = disabled === true);
223
+ useOnValueChange(element, () => droppable.element = element);
224
+ useOnValueChange(type, () => droppable.id = id);
225
+ useEffect(() => {
226
+ return droppable.destroy;
227
+ }, [droppable]);
228
+ return {
229
+ get isDisabled() {
230
+ return isDisabled.value;
231
+ },
232
+ get isDropTarget() {
233
+ return isDropTarget.value;
234
+ },
235
+ ref: useCallback(
236
+ (element2) => {
237
+ droppable.element = element2 ?? void 0;
238
+ },
239
+ [droppable]
240
+ )
241
+ };
242
+ }
243
+
244
+ export { DragDropProvider, useDragDropManager, useDragOperation, useDraggable, useDroppable };
245
+ //# sourceMappingURL=out.js.map
246
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@dnd-kit/react",
3
+ "version": "0.0.1",
4
+ "main": "./index.cjs",
5
+ "module": "./index.js",
6
+ "type": "module",
7
+ "types": "./index.d.ts",
8
+ "sideEffects": false,
9
+ "license": "MIT",
10
+ "files": [
11
+ "LICENSE",
12
+ "README.md",
13
+ "index.js",
14
+ "index.d.ts",
15
+ "index.cjs",
16
+ "hooks.js",
17
+ "hooks.d.ts",
18
+ "hooks.cjs",
19
+ "sortable.js",
20
+ "sortable.d.ts",
21
+ "sortable.cjs",
22
+ "utilities.js",
23
+ "utilities.d.ts",
24
+ "utilities.cjs"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "types": "./index.d.ts",
29
+ "import": "./index.js",
30
+ "require": "./index.cjs"
31
+ },
32
+ "./hooks": {
33
+ "types": "./hooks.d.ts",
34
+ "import": "./hooks.js",
35
+ "require": "./hooks.cjs"
36
+ },
37
+ "./sortable": {
38
+ "types": "./sortable.d.ts",
39
+ "import": "./sortable.js",
40
+ "require": "./sortable.cjs"
41
+ },
42
+ "./utilities": {
43
+ "types": "./utilities.d.ts",
44
+ "import": "./utilities.js",
45
+ "require": "./utilities.cjs"
46
+ }
47
+ },
48
+ "scripts": {
49
+ "build": "bun build:hooks && bun build:utilities && bun build:core && bun build:sortable",
50
+ "build:core": "tsup src/core/index.ts",
51
+ "build:hooks": "tsup --entry.hooks src/hooks/index.ts",
52
+ "build:sortable": "tsup --entry.sortable src/sortable/index.ts",
53
+ "build:utilities": "tsup --entry.utilities src/utilities/index.ts",
54
+ "dev": "bun build:hooks --watch & bun build:utilities --watch & bun build:core --watch & bun build:sortable --watch",
55
+ "lint": "TIMING=1 eslint src/**/*.ts* --fix",
56
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
57
+ },
58
+ "dependencies": {
59
+ "@dnd-kit/abstract": "*",
60
+ "@dnd-kit/dom": "*",
61
+ "@dnd-kit/state": "*",
62
+ "tslib": "^2.6.2"
63
+ },
64
+ "peerDependencies": {
65
+ "react": "^18.0.0",
66
+ "react-dom": "^18.0.0"
67
+ },
68
+ "devDependencies": {
69
+ "@types/react": "^18.0.9",
70
+ "@types/react-dom": "^18.0.4",
71
+ "eslint": "^8.38.0",
72
+ "@dnd-kit/eslint-config": "*",
73
+ "react": "^18.1.0",
74
+ "tsup": "^7.2.0",
75
+ "typescript": "^5.1.6"
76
+ },
77
+ "publishConfig": {
78
+ "access": "public"
79
+ }
80
+ }
package/sortable.cjs ADDED
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ var react$1 = require('react');
4
+ var state = require('@dnd-kit/state');
5
+ var sortable = require('@dnd-kit/dom/sortable');
6
+ var react = require('@dnd-kit/react');
7
+ var hooks = require('@dnd-kit/react/hooks');
8
+ var utilities = require('@dnd-kit/react/utilities');
9
+
10
+ // src/sortable/useSortable.ts
11
+ function useSortable(input) {
12
+ const {
13
+ accept,
14
+ collisionDetector,
15
+ collisionPriority,
16
+ id,
17
+ data,
18
+ index,
19
+ disabled,
20
+ sensors,
21
+ transition = sortable.defaultSortableTransition,
22
+ type
23
+ } = input;
24
+ const feedback = typeof input.feedback === "function" ? "none" : input.feedback;
25
+ const manager = react.useDragDropManager();
26
+ const handle = utilities.getCurrentValue(input.handle);
27
+ const element = utilities.getCurrentValue(input.element);
28
+ const sortable$1 = hooks.useConstant(
29
+ () => new sortable.Sortable(
30
+ {
31
+ ...input,
32
+ handle,
33
+ element,
34
+ feedback
35
+ },
36
+ manager
37
+ ),
38
+ manager
39
+ );
40
+ const isDisabled = hooks.useComputed(() => sortable$1.disabled);
41
+ const isDropTarget = hooks.useComputed(() => sortable$1.isDropTarget);
42
+ const isDragSource = hooks.useComputed(() => sortable$1.isDragSource);
43
+ hooks.useOnValueChange(
44
+ accept,
45
+ () => sortable$1.accept = accept,
46
+ void 0,
47
+ state.deepEqual
48
+ );
49
+ hooks.useOnValueChange(type, () => sortable$1.type = type);
50
+ hooks.useOnValueChange(id, () => sortable$1.id = id);
51
+ hooks.useOnValueChange(data, () => sortable$1.data = data ?? null);
52
+ hooks.useOnValueChange(
53
+ index,
54
+ () => {
55
+ if (manager.dragOperation.status.idle && transition) {
56
+ sortable$1.refreshShape();
57
+ }
58
+ },
59
+ hooks.useImmediateEffect
60
+ );
61
+ hooks.useOnValueChange(index, () => sortable$1.index = index, hooks.useIsomorphicLayoutEffect);
62
+ hooks.useOnValueChange(handle, () => sortable$1.handle = handle);
63
+ hooks.useOnValueChange(element, () => sortable$1.element = element);
64
+ hooks.useOnValueChange(disabled, () => sortable$1.disabled = disabled === true);
65
+ hooks.useOnValueChange(sensors, () => sortable$1.sensors = sensors);
66
+ hooks.useOnValueChange(
67
+ collisionDetector,
68
+ () => sortable$1.collisionDetector = collisionDetector
69
+ );
70
+ hooks.useOnValueChange(
71
+ collisionPriority,
72
+ () => sortable$1.collisionPriority = collisionPriority
73
+ );
74
+ hooks.useOnValueChange(
75
+ input.feedback,
76
+ () => sortable$1.feedback = feedback ?? "default"
77
+ );
78
+ hooks.useOnValueChange(transition, () => sortable$1.transition = transition);
79
+ react$1.useEffect(() => {
80
+ return sortable$1.destroy;
81
+ }, [sortable$1]);
82
+ return {
83
+ get isDisabled() {
84
+ return isDisabled.value;
85
+ },
86
+ get isDragSource() {
87
+ return isDragSource.value;
88
+ },
89
+ get isDropTarget() {
90
+ return isDropTarget.value;
91
+ },
92
+ handleRef: react$1.useCallback(
93
+ (element2) => {
94
+ sortable$1.handle = element2 ?? void 0;
95
+ },
96
+ [sortable$1]
97
+ ),
98
+ ref: react$1.useCallback(
99
+ (element2) => {
100
+ sortable$1.element = element2 ?? void 0;
101
+ },
102
+ [sortable$1]
103
+ ),
104
+ sourceRef: react$1.useCallback(
105
+ (element2) => {
106
+ sortable$1.source = element2 ?? void 0;
107
+ },
108
+ [sortable$1]
109
+ ),
110
+ targetRef: react$1.useCallback(
111
+ (element2) => {
112
+ sortable$1.target = element2 ?? void 0;
113
+ },
114
+ [sortable$1]
115
+ )
116
+ };
117
+ }
118
+
119
+ exports.useSortable = useSortable;
120
+ //# sourceMappingURL=out.js.map
121
+ //# sourceMappingURL=sortable.cjs.map
package/sortable.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { Data } from '@dnd-kit/abstract';
2
+ import { SortableInput } from '@dnd-kit/dom/sortable';
3
+ import { RefOrValue } from '@dnd-kit/react/utilities';
4
+ import { FeedbackType } from '@dnd-kit/dom';
5
+
6
+ interface UseSortableInput<T extends Data = Data> extends Omit<SortableInput<T>, 'handle' | 'element' | 'feedback'> {
7
+ handle?: RefOrValue<Element>;
8
+ element?: RefOrValue<Element>;
9
+ feedback?: FeedbackType | (() => React.ReactNode);
10
+ }
11
+ declare function useSortable<T extends Data = Data>(input: UseSortableInput<T>): {
12
+ readonly isDisabled: boolean;
13
+ readonly isDragSource: boolean;
14
+ readonly isDropTarget: boolean;
15
+ handleRef: (element: Element | null) => void;
16
+ ref: (element: Element | null) => void;
17
+ sourceRef: (element: Element | null) => void;
18
+ targetRef: (element: Element | null) => void;
19
+ };
20
+
21
+ export { UseSortableInput, useSortable };
package/sortable.js ADDED
@@ -0,0 +1,119 @@
1
+ import { useEffect, useCallback } from 'react';
2
+ import { deepEqual } from '@dnd-kit/state';
3
+ import { Sortable, defaultSortableTransition } from '@dnd-kit/dom/sortable';
4
+ import { useDragDropManager } from '@dnd-kit/react';
5
+ import { useConstant, useComputed, useOnValueChange, useImmediateEffect, useIsomorphicLayoutEffect } from '@dnd-kit/react/hooks';
6
+ import { getCurrentValue } from '@dnd-kit/react/utilities';
7
+
8
+ // src/sortable/useSortable.ts
9
+ function useSortable(input) {
10
+ const {
11
+ accept,
12
+ collisionDetector,
13
+ collisionPriority,
14
+ id,
15
+ data,
16
+ index,
17
+ disabled,
18
+ sensors,
19
+ transition = defaultSortableTransition,
20
+ type
21
+ } = input;
22
+ const feedback = typeof input.feedback === "function" ? "none" : input.feedback;
23
+ const manager = useDragDropManager();
24
+ const handle = getCurrentValue(input.handle);
25
+ const element = getCurrentValue(input.element);
26
+ const sortable = useConstant(
27
+ () => new Sortable(
28
+ {
29
+ ...input,
30
+ handle,
31
+ element,
32
+ feedback
33
+ },
34
+ manager
35
+ ),
36
+ manager
37
+ );
38
+ const isDisabled = useComputed(() => sortable.disabled);
39
+ const isDropTarget = useComputed(() => sortable.isDropTarget);
40
+ const isDragSource = useComputed(() => sortable.isDragSource);
41
+ useOnValueChange(
42
+ accept,
43
+ () => sortable.accept = accept,
44
+ void 0,
45
+ deepEqual
46
+ );
47
+ useOnValueChange(type, () => sortable.type = type);
48
+ useOnValueChange(id, () => sortable.id = id);
49
+ useOnValueChange(data, () => sortable.data = data ?? null);
50
+ useOnValueChange(
51
+ index,
52
+ () => {
53
+ if (manager.dragOperation.status.idle && transition) {
54
+ sortable.refreshShape();
55
+ }
56
+ },
57
+ useImmediateEffect
58
+ );
59
+ useOnValueChange(index, () => sortable.index = index, useIsomorphicLayoutEffect);
60
+ useOnValueChange(handle, () => sortable.handle = handle);
61
+ useOnValueChange(element, () => sortable.element = element);
62
+ useOnValueChange(disabled, () => sortable.disabled = disabled === true);
63
+ useOnValueChange(sensors, () => sortable.sensors = sensors);
64
+ useOnValueChange(
65
+ collisionDetector,
66
+ () => sortable.collisionDetector = collisionDetector
67
+ );
68
+ useOnValueChange(
69
+ collisionPriority,
70
+ () => sortable.collisionPriority = collisionPriority
71
+ );
72
+ useOnValueChange(
73
+ input.feedback,
74
+ () => sortable.feedback = feedback ?? "default"
75
+ );
76
+ useOnValueChange(transition, () => sortable.transition = transition);
77
+ useEffect(() => {
78
+ return sortable.destroy;
79
+ }, [sortable]);
80
+ return {
81
+ get isDisabled() {
82
+ return isDisabled.value;
83
+ },
84
+ get isDragSource() {
85
+ return isDragSource.value;
86
+ },
87
+ get isDropTarget() {
88
+ return isDropTarget.value;
89
+ },
90
+ handleRef: useCallback(
91
+ (element2) => {
92
+ sortable.handle = element2 ?? void 0;
93
+ },
94
+ [sortable]
95
+ ),
96
+ ref: useCallback(
97
+ (element2) => {
98
+ sortable.element = element2 ?? void 0;
99
+ },
100
+ [sortable]
101
+ ),
102
+ sourceRef: useCallback(
103
+ (element2) => {
104
+ sortable.source = element2 ?? void 0;
105
+ },
106
+ [sortable]
107
+ ),
108
+ targetRef: useCallback(
109
+ (element2) => {
110
+ sortable.target = element2 ?? void 0;
111
+ },
112
+ [sortable]
113
+ )
114
+ };
115
+ }
116
+
117
+ export { useSortable };
118
+ //# sourceMappingURL=out.js.map
119
+ //# sourceMappingURL=sortable.js.map
package/utilities.cjs ADDED
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ // src/utilities/getCurrentValue.ts
4
+ function getCurrentValue(value) {
5
+ if (value == null) {
6
+ return void 0;
7
+ }
8
+ if (typeof value === "object" && "current" in value) {
9
+ return value.current ?? void 0;
10
+ }
11
+ return value;
12
+ }
13
+
14
+ exports.getCurrentValue = getCurrentValue;
15
+ //# sourceMappingURL=out.js.map
16
+ //# sourceMappingURL=utilities.cjs.map
package/utilities.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { RefObject, MutableRefObject } from 'react';
2
+
3
+ type RefOrValue<T> = T | RefObject<T | null | undefined> | MutableRefObject<T> | null | undefined;
4
+ declare function getCurrentValue<T>(value: RefOrValue<T>): NonNullable<T> | undefined;
5
+
6
+ export { RefOrValue, getCurrentValue };
package/utilities.js ADDED
@@ -0,0 +1,14 @@
1
+ // src/utilities/getCurrentValue.ts
2
+ function getCurrentValue(value) {
3
+ if (value == null) {
4
+ return void 0;
5
+ }
6
+ if (typeof value === "object" && "current" in value) {
7
+ return value.current ?? void 0;
8
+ }
9
+ return value;
10
+ }
11
+
12
+ export { getCurrentValue };
13
+ //# sourceMappingURL=out.js.map
14
+ //# sourceMappingURL=utilities.js.map