@mk-drag-and-drop/react 0.1.0

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.
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo, useLayoutEffect, useRef, } from "react";
3
+ export const DragOverlayHost = memo(function DragOverlayHost({ dragState, children, contentId, onHostReady, onOverlayRectChange, }) {
4
+ const overlayWrapperRef = useRef(null);
5
+ useLayoutEffect(() => {
6
+ const wrapper = overlayWrapperRef.current;
7
+ if (!wrapper) {
8
+ onHostReady?.(null);
9
+ return;
10
+ }
11
+ const host = {
12
+ move: (nextDragState) => {
13
+ moveOverlayWrapper(wrapper, nextDragState);
14
+ },
15
+ };
16
+ onHostReady?.(host);
17
+ host.move(dragState);
18
+ return () => {
19
+ onHostReady?.(null);
20
+ };
21
+ }, [dragState, onHostReady]);
22
+ useLayoutEffect(() => {
23
+ const wrapper = overlayWrapperRef.current;
24
+ if (!wrapper) {
25
+ onOverlayRectChange?.(null);
26
+ return;
27
+ }
28
+ const measuredElement = wrapper.firstElementChild ?? wrapper;
29
+ const measureOverlayElement = () => {
30
+ if (!measuredElement.isConnected) {
31
+ return;
32
+ }
33
+ onOverlayRectChange?.(domRectToDragRect(measuredElement.getBoundingClientRect()));
34
+ };
35
+ measureOverlayElement();
36
+ if (typeof ResizeObserver === "undefined") {
37
+ return () => {
38
+ onOverlayRectChange?.(null);
39
+ };
40
+ }
41
+ const resizeObserver = new ResizeObserver(() => {
42
+ measureOverlayElement();
43
+ });
44
+ resizeObserver.observe(measuredElement);
45
+ return () => {
46
+ resizeObserver.disconnect();
47
+ onOverlayRectChange?.(null);
48
+ };
49
+ }, [contentId, onOverlayRectChange]);
50
+ return (_jsx("div", { ref: overlayWrapperRef, style: {
51
+ position: "fixed",
52
+ left: dragState.sourceRect.left,
53
+ top: dragState.sourceRect.top,
54
+ width: dragState.sourceRect.width,
55
+ height: dragState.sourceRect.height,
56
+ pointerEvents: "none",
57
+ zIndex: 9999,
58
+ transform: getOverlayTransform(dragState),
59
+ }, children: children }));
60
+ });
61
+ function moveOverlayWrapper(wrapper, dragState) {
62
+ wrapper.style.transform = getOverlayTransform(dragState);
63
+ }
64
+ function getOverlayTransform(dragState) {
65
+ const x = dragState.pointerPosition.x - dragState.startPointerPosition.x;
66
+ const y = dragState.pointerPosition.y - dragState.startPointerPosition.y;
67
+ return `translate3d(${x}px, ${y}px, 0)`;
68
+ }
69
+ function domRectToDragRect(rect) {
70
+ return {
71
+ x: rect.x,
72
+ y: rect.y,
73
+ top: rect.top,
74
+ right: rect.right,
75
+ bottom: rect.bottom,
76
+ left: rect.left,
77
+ width: rect.width,
78
+ height: rect.height,
79
+ };
80
+ }
@@ -0,0 +1,21 @@
1
+ import { type ReactNode } from "react";
2
+ import { type DragEndEvent, type DragLifecycleCallbacks, type DragModifierInput, type DragStartEvent, type DragUpdateEvent, type DropEvent, type KeyboardConfiguration, type PointerConfiguration, type TargetingAlgorithm, type TargetingConstraint } from "@mk-drag-and-drop/dom";
3
+ import { type DragOverlayInput } from "./drag-overlay.js";
4
+ export type DragAnnouncements = {
5
+ onDragStart?: (event: DragStartEvent) => string | null;
6
+ onDragUpdate?: (event: DragUpdateEvent) => string | null;
7
+ onDragEnd?: (event: DragEndEvent) => string | null;
8
+ onDrop?: (event: DropEvent) => string | null;
9
+ };
10
+ export type DragProviderProps = {
11
+ children: ReactNode;
12
+ announcements?: DragAnnouncements;
13
+ dragOverlay?: (overlay: DragOverlayInput) => ReactNode;
14
+ keyboardConfiguration?: KeyboardConfiguration;
15
+ keepOverlayOnDrop?: boolean;
16
+ modifiers?: readonly DragModifierInput[];
17
+ pointerConfiguration?: PointerConfiguration;
18
+ targetingAlgorithm?: TargetingAlgorithm;
19
+ targetingConstraint?: TargetingConstraint;
20
+ } & DragLifecycleCallbacks;
21
+ export declare function DragProvider({ children, announcements, dragOverlay, keyboardConfiguration, keepOverlayOnDrop, modifiers, pointerConfiguration, targetingAlgorithm, targetingConstraint, onDragStart, onDragUpdate, onDragEnd, onDrop, }: DragProviderProps): import("react").JSX.Element;
@@ -0,0 +1,293 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
3
+ import { pointerToCenter, } from "@mk-drag-and-drop/dom";
4
+ import { createDragRuntimeHandle, } from "@mk-drag-and-drop/dom/integration";
5
+ import { DragContext } from "./drag-context.js";
6
+ import { DragOverlayHost, } from "./drag-overlay.js";
7
+ const visuallyHiddenStyle = {
8
+ position: "absolute",
9
+ width: 1,
10
+ height: 1,
11
+ padding: 0,
12
+ margin: -1,
13
+ overflow: "hidden",
14
+ clip: "rect(0 0 0 0)",
15
+ whiteSpace: "nowrap",
16
+ border: 0,
17
+ };
18
+ export function DragProvider({ children, announcements, dragOverlay, keyboardConfiguration, keepOverlayOnDrop = false, modifiers, pointerConfiguration, targetingAlgorithm = pointerToCenter, targetingConstraint, onDragStart, onDragUpdate, onDragEnd, onDrop, }) {
19
+ const [overlayRequest, setOverlayRequest] = useState(null);
20
+ const [announcementState, setAnnouncementState] = useState({
21
+ id: 0,
22
+ message: "",
23
+ });
24
+ const lastAnnouncementRef = useRef(null);
25
+ const runtimeRef = useRef(null);
26
+ const dragOverlayRef = useRef(dragOverlay);
27
+ const overlayHostRef = useRef(null);
28
+ const overlayContentIdRef = useRef(0);
29
+ const overlaySnapshotRef = useRef(null);
30
+ const pendingOverlayDragStateRef = useRef(null);
31
+ const latestLifecyclePropsRef = useRef({
32
+ announcements,
33
+ onDragStart,
34
+ onDragUpdate,
35
+ onDragEnd,
36
+ onDrop,
37
+ });
38
+ const lifecycleCallbacksRef = useRef(null);
39
+ const runtimeConfigurationSnapshotRef = useRef(null);
40
+ const keyboardDragEnabled = isKeyboardDragEnabledFromConfiguration(keyboardConfiguration);
41
+ const finishOverlay = useCallback(() => {
42
+ pendingOverlayDragStateRef.current = null;
43
+ overlayHostRef.current = null;
44
+ overlaySnapshotRef.current = null;
45
+ setOverlayRequest(null);
46
+ runtimeRef.current?.setOverlayRect(null);
47
+ }, []);
48
+ if (lifecycleCallbacksRef.current === null) {
49
+ lifecycleCallbacksRef.current = {
50
+ onDragStart: (event, helpers) => {
51
+ const { announcements, onDragStart } = latestLifecyclePropsRef.current;
52
+ onDragStart?.(event, helpers);
53
+ announce(announcements?.onDragStart?.(event));
54
+ },
55
+ onDragUpdate: (event, helpers) => {
56
+ const { announcements, onDragUpdate } = latestLifecyclePropsRef.current;
57
+ onDragUpdate?.(event, helpers);
58
+ if (event.activeDropTargetId !== event.previousDropTargetId) {
59
+ announce(announcements?.onDragUpdate?.(event));
60
+ }
61
+ },
62
+ onDragEnd: (event, helpers) => {
63
+ const { announcements, onDragEnd } = latestLifecyclePropsRef.current;
64
+ onDragEnd?.(event, helpers);
65
+ announce(announcements?.onDragEnd?.(event));
66
+ },
67
+ onDrop: (event, helpers) => {
68
+ const { announcements, onDrop } = latestLifecyclePropsRef.current;
69
+ onDrop?.(event, helpers);
70
+ announce(announcements?.onDrop?.(event));
71
+ },
72
+ };
73
+ }
74
+ if (runtimeRef.current === null) {
75
+ runtimeRef.current = createDragRuntimeHandle({
76
+ updateOverlayHost: handleOverlayHostUpdate,
77
+ });
78
+ }
79
+ const runtime = runtimeRef.current;
80
+ const contextValue = useMemo(() => ({
81
+ runtime,
82
+ keyboardDragEnabled,
83
+ }), [keyboardDragEnabled, runtime]);
84
+ const nextRuntimeConfiguration = {
85
+ targetingAlgorithm,
86
+ targetingConstraint,
87
+ hasDragOverlay: dragOverlay !== undefined,
88
+ keepOverlayOnDrop,
89
+ lifecycleCallbacks: lifecycleCallbacksRef.current,
90
+ keyboardConfiguration,
91
+ modifiers,
92
+ pointerConfiguration,
93
+ };
94
+ useLayoutEffect(() => {
95
+ dragOverlayRef.current = dragOverlay;
96
+ latestLifecyclePropsRef.current = {
97
+ announcements,
98
+ onDragStart,
99
+ onDragUpdate,
100
+ onDragEnd,
101
+ onDrop,
102
+ };
103
+ });
104
+ useLayoutEffect(() => {
105
+ if (areRuntimeConfigurationSnapshotsEqual(runtimeConfigurationSnapshotRef.current, nextRuntimeConfiguration)) {
106
+ return;
107
+ }
108
+ runtime.configure(nextRuntimeConfiguration);
109
+ runtimeConfigurationSnapshotRef.current =
110
+ createRuntimeConfigurationSnapshot(nextRuntimeConfiguration);
111
+ });
112
+ useEffect(() => {
113
+ return () => {
114
+ runtime.dispose();
115
+ };
116
+ }, [runtime]);
117
+ useEffect(() => {
118
+ if (!dragOverlay) {
119
+ finishOverlay();
120
+ }
121
+ }, [dragOverlay, finishOverlay]);
122
+ useEffect(() => {
123
+ if (!announcements) {
124
+ lastAnnouncementRef.current = null;
125
+ }
126
+ }, [announcements]);
127
+ function announce(message) {
128
+ if (!message || message === lastAnnouncementRef.current) {
129
+ return;
130
+ }
131
+ lastAnnouncementRef.current = message;
132
+ setAnnouncementState((currentAnnouncementState) => ({
133
+ id: currentAnnouncementState.id + 1,
134
+ message,
135
+ }));
136
+ }
137
+ const handleOverlayRectChange = useCallback((overlayRect) => {
138
+ runtimeRef.current?.setOverlayRect(overlayRect);
139
+ }, []);
140
+ const handleOverlayHostReady = useCallback((host) => {
141
+ overlayHostRef.current = host;
142
+ if (host && pendingOverlayDragStateRef.current) {
143
+ host.move(pendingOverlayDragStateRef.current);
144
+ }
145
+ }, []);
146
+ const overlaySnapshot = getOverlaySnapshot();
147
+ return (_jsxs(DragContext, { value: contextValue, children: [children, overlaySnapshot ? (_jsx(DragOverlayHost, { contentId: overlaySnapshot.id, dragState: overlaySnapshot.state.dragState, onHostReady: handleOverlayHostReady, onOverlayRectChange: handleOverlayRectChange, children: overlaySnapshot.content })) : null, announcements ? (_jsx("div", { "aria-atomic": "true", "aria-live": "polite", style: visuallyHiddenStyle, children: announcementState.message ? (_jsx("span", { children: announcementState.message }, announcementState.id)) : null })) : null] }));
148
+ function handleOverlayHostUpdate(update) {
149
+ if (update.type === "mount" || update.type === "release") {
150
+ mountOverlay(update.state);
151
+ return;
152
+ }
153
+ if (update.type === "move") {
154
+ moveOverlay(update.dragState);
155
+ return;
156
+ }
157
+ finishOverlay();
158
+ }
159
+ function mountOverlay(state) {
160
+ pendingOverlayDragStateRef.current = state.dragState;
161
+ overlayHostRef.current?.move(state.dragState);
162
+ if (!dragOverlayRef.current) {
163
+ finishOverlay();
164
+ return;
165
+ }
166
+ overlayContentIdRef.current += 1;
167
+ setOverlayRequest({
168
+ id: overlayContentIdRef.current,
169
+ state,
170
+ });
171
+ }
172
+ function moveOverlay(dragState) {
173
+ pendingOverlayDragStateRef.current = dragState;
174
+ overlayHostRef.current?.move(dragState);
175
+ }
176
+ function getOverlaySnapshot() {
177
+ if (!overlayRequest || !dragOverlay) {
178
+ overlaySnapshotRef.current = null;
179
+ return null;
180
+ }
181
+ if (overlaySnapshotRef.current?.id === overlayRequest.id) {
182
+ return overlaySnapshotRef.current;
183
+ }
184
+ overlaySnapshotRef.current = {
185
+ id: overlayRequest.id,
186
+ state: overlayRequest.state,
187
+ content: dragOverlay({
188
+ dragState: overlayRequest.state.dragState,
189
+ phase: overlayRequest.state.phase,
190
+ finish: finishOverlay,
191
+ }),
192
+ };
193
+ return overlaySnapshotRef.current;
194
+ }
195
+ }
196
+ function createRuntimeConfigurationSnapshot(input) {
197
+ return {
198
+ targetingAlgorithm: input.targetingAlgorithm,
199
+ targetingConstraint: input.targetingConstraint,
200
+ hasDragOverlay: input.hasDragOverlay,
201
+ keepOverlayOnDrop: input.keepOverlayOnDrop,
202
+ keyboardConfiguration: cloneKeyboardConfiguration(input.keyboardConfiguration),
203
+ modifiers: input.modifiers ? Array.from(input.modifiers) : undefined,
204
+ pointerConfiguration: input.pointerConfiguration
205
+ ? { ...input.pointerConfiguration }
206
+ : undefined,
207
+ };
208
+ }
209
+ function areRuntimeConfigurationSnapshotsEqual(previous, next) {
210
+ return (previous !== null &&
211
+ previous.targetingAlgorithm === next.targetingAlgorithm &&
212
+ previous.targetingConstraint === next.targetingConstraint &&
213
+ previous.hasDragOverlay === next.hasDragOverlay &&
214
+ previous.keepOverlayOnDrop === next.keepOverlayOnDrop &&
215
+ areKeyboardConfigurationsEqual(previous.keyboardConfiguration, next.keyboardConfiguration) &&
216
+ arePointerConfigurationsEqual(previous.pointerConfiguration, next.pointerConfiguration) &&
217
+ areModifierInputsEqual(previous.modifiers, next.modifiers));
218
+ }
219
+ function cloneKeyboardConfiguration(keyboardConfiguration) {
220
+ if (!keyboardConfiguration) {
221
+ return undefined;
222
+ }
223
+ return {
224
+ enabled: keyboardConfiguration.enabled,
225
+ start: cloneKeyboardCommand(keyboardConfiguration.start),
226
+ drop: cloneKeyboardCommand(keyboardConfiguration.drop),
227
+ cancel: cloneKeyboardCommand(keyboardConfiguration.cancel),
228
+ moveUp: cloneKeyboardCommand(keyboardConfiguration.moveUp),
229
+ moveDown: cloneKeyboardCommand(keyboardConfiguration.moveDown),
230
+ moveLeft: cloneKeyboardCommand(keyboardConfiguration.moveLeft),
231
+ moveRight: cloneKeyboardCommand(keyboardConfiguration.moveRight),
232
+ moveDistance: keyboardConfiguration.moveDistance,
233
+ };
234
+ }
235
+ function cloneKeyboardCommand(command) {
236
+ return Array.isArray(command) ? Array.from(command) : command;
237
+ }
238
+ function areKeyboardConfigurationsEqual(previous, next) {
239
+ if (previous === next) {
240
+ return true;
241
+ }
242
+ if (!previous || !next) {
243
+ return false;
244
+ }
245
+ return (previous.enabled === next.enabled &&
246
+ previous.moveDistance === next.moveDistance &&
247
+ areKeyboardCommandsEqual(previous.start, next.start) &&
248
+ areKeyboardCommandsEqual(previous.drop, next.drop) &&
249
+ areKeyboardCommandsEqual(previous.cancel, next.cancel) &&
250
+ areKeyboardCommandsEqual(previous.moveUp, next.moveUp) &&
251
+ areKeyboardCommandsEqual(previous.moveDown, next.moveDown) &&
252
+ areKeyboardCommandsEqual(previous.moveLeft, next.moveLeft) &&
253
+ areKeyboardCommandsEqual(previous.moveRight, next.moveRight));
254
+ }
255
+ function areKeyboardCommandsEqual(previous, next) {
256
+ if (previous === next) {
257
+ return true;
258
+ }
259
+ if (previous === undefined || next === undefined) {
260
+ return false;
261
+ }
262
+ if (typeof previous === "string" || typeof next === "string") {
263
+ return (typeof previous === "string" &&
264
+ typeof next === "string" &&
265
+ normalizeKeyboardKey(previous) === normalizeKeyboardKey(next));
266
+ }
267
+ if (previous.length !== next.length) {
268
+ return false;
269
+ }
270
+ return previous.every((key, index) => normalizeKeyboardKey(key) === normalizeKeyboardKey(next[index]));
271
+ }
272
+ function normalizeKeyboardKey(key) {
273
+ return key === " " ? "Space" : key;
274
+ }
275
+ function arePointerConfigurationsEqual(previous, next) {
276
+ return (previous === next ||
277
+ (previous !== undefined &&
278
+ next !== undefined &&
279
+ previous.activationDelay === next.activationDelay &&
280
+ previous.activationDistance === next.activationDistance));
281
+ }
282
+ function areModifierInputsEqual(previous, next) {
283
+ if (previous === next) {
284
+ return true;
285
+ }
286
+ if (!previous || !next || previous.length !== next.length) {
287
+ return false;
288
+ }
289
+ return previous.every((modifier, index) => modifier === next[index]);
290
+ }
291
+ function isKeyboardDragEnabledFromConfiguration(keyboardConfiguration) {
292
+ return keyboardConfiguration?.enabled ?? true;
293
+ }
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from "react";
2
+ export type UseDragHandleResult<ElementType extends HTMLElement = HTMLElement> = HTMLAttributes<ElementType> & {
3
+ "data-dnd-drag-handle": string;
4
+ };
5
+ export declare function useDragHandle<ElementType extends HTMLElement = HTMLElement>(): UseDragHandleResult<ElementType>;
@@ -0,0 +1,7 @@
1
+ import { domDragHandleAttribute } from "@mk-drag-and-drop/dom/integration";
2
+ const dragHandleProps = {
3
+ [domDragHandleAttribute]: "true",
4
+ };
5
+ export function useDragHandle() {
6
+ return dragHandleProps;
7
+ }
@@ -0,0 +1,9 @@
1
+ import { type HTMLAttributes, type RefCallback } from "react";
2
+ export type UseDraggableOptions = {
3
+ draggableId: string;
4
+ group?: string;
5
+ };
6
+ export type UseDraggableResult<ElementType extends HTMLElement = HTMLElement> = HTMLAttributes<ElementType> & {
7
+ ref: RefCallback<ElementType>;
8
+ };
9
+ export declare function useDraggable<ElementType extends HTMLElement = HTMLElement>({ draggableId, group, }: UseDraggableOptions): UseDraggableResult<ElementType>;
@@ -0,0 +1,36 @@
1
+ import { useCallback, useContext, useMemo, useRef, } from "react";
2
+ import { createDomDraggable } from "@mk-drag-and-drop/dom/integration";
3
+ import { DragContext } from "../drag-context.js";
4
+ const defaultDraggableGroup = "default";
5
+ export function useDraggable({ draggableId, group = defaultDraggableGroup, }) {
6
+ const context = useContext(DragContext);
7
+ const nodeRef = useRef(null);
8
+ if (!context) {
9
+ throw new Error("useDraggable must be used inside DragProvider");
10
+ }
11
+ const { runtime, keyboardDragEnabled } = context;
12
+ const setNodeRef = useCallback((node) => {
13
+ nodeRef.current = node;
14
+ }, []);
15
+ const getNode = useCallback(() => nodeRef.current, []);
16
+ const behavior = useMemo(() => createDomDraggable({
17
+ draggableId,
18
+ group,
19
+ runtime,
20
+ getElement: getNode,
21
+ keyboardDragEnabled,
22
+ }), [getNode, group, draggableId, keyboardDragEnabled, runtime]);
23
+ return useMemo(() => {
24
+ const dragProps = {
25
+ ref: setNodeRef,
26
+ onPointerDown: behavior.onPointerDown,
27
+ };
28
+ return behavior.tabIndex !== undefined
29
+ ? {
30
+ ...dragProps,
31
+ tabIndex: behavior.tabIndex,
32
+ onKeyDown: behavior.onKeyDown,
33
+ }
34
+ : dragProps;
35
+ }, [behavior, setNodeRef]);
36
+ }
@@ -0,0 +1,9 @@
1
+ import { type RefCallback } from "react";
2
+ export type UseDropContainerOptions = {
3
+ containerId: string;
4
+ group?: string;
5
+ };
6
+ export type UseDropContainerResult<ElementType extends HTMLElement = HTMLElement> = {
7
+ ref: RefCallback<ElementType>;
8
+ };
9
+ export declare function useDropContainer<ElementType extends HTMLElement = HTMLElement>({ containerId, group, }: UseDropContainerOptions): UseDropContainerResult<ElementType>;
@@ -0,0 +1,56 @@
1
+ import { useCallback, useContext, useEffect, useMemo, useRef, } from "react";
2
+ import { createDomDropContainer, } from "@mk-drag-and-drop/dom/integration";
3
+ import { DragContext } from "../drag-context.js";
4
+ const defaultDropContainerGroup = "default";
5
+ export function useDropContainer({ containerId, group = defaultDropContainerGroup, }) {
6
+ const context = useContext(DragContext);
7
+ const nodeRef = useRef(null);
8
+ const behaviorRef = useRef(null);
9
+ if (!context) {
10
+ throw new Error("useDropContainer must be used inside DragProvider");
11
+ }
12
+ const { runtime } = context;
13
+ const getElement = useCallback(() => nodeRef.current, []);
14
+ const getBehavior = useCallback(() => {
15
+ const existingBehavior = behaviorRef.current;
16
+ if (existingBehavior &&
17
+ existingBehavior.runtime === runtime &&
18
+ existingBehavior.containerId === containerId &&
19
+ existingBehavior.group === group) {
20
+ return existingBehavior.behavior;
21
+ }
22
+ existingBehavior?.behavior.cleanup();
23
+ const behavior = createDomDropContainer({
24
+ runtime,
25
+ containerId,
26
+ group,
27
+ getElement,
28
+ });
29
+ behaviorRef.current = {
30
+ runtime,
31
+ containerId,
32
+ group,
33
+ behavior,
34
+ };
35
+ return behavior;
36
+ }, [containerId, getElement, group, runtime]);
37
+ const setNodeRef = useCallback((node) => {
38
+ nodeRef.current = node;
39
+ getBehavior().setElement(node);
40
+ }, [getBehavior]);
41
+ useEffect(() => {
42
+ const behavior = getBehavior();
43
+ if (nodeRef.current) {
44
+ behavior.setElement(nodeRef.current);
45
+ }
46
+ return () => {
47
+ behavior.cleanup();
48
+ if (behaviorRef.current?.behavior === behavior) {
49
+ behaviorRef.current = null;
50
+ }
51
+ };
52
+ }, [getBehavior]);
53
+ return useMemo(() => ({
54
+ ref: setNodeRef,
55
+ }), [setNodeRef]);
56
+ }
@@ -0,0 +1,10 @@
1
+ import { type HTMLAttributes, type RefCallback } from "react";
2
+ export type UseDroppableOptions = {
3
+ dropTargetId: string;
4
+ group?: string;
5
+ containerId?: string | null;
6
+ };
7
+ export type UseDroppableResult<ElementType extends HTMLElement = HTMLElement> = HTMLAttributes<ElementType> & {
8
+ ref: RefCallback<ElementType>;
9
+ };
10
+ export declare function useDroppable<ElementType extends HTMLElement = HTMLElement>({ dropTargetId, group, containerId, }: UseDroppableOptions): UseDroppableResult<ElementType>;
@@ -0,0 +1,23 @@
1
+ import { useCallback, useContext, useMemo, } from "react";
2
+ import { createDomDroppable } from "@mk-drag-and-drop/dom/integration";
3
+ import { DragContext } from "../drag-context.js";
4
+ const defaultDroppableGroup = "default";
5
+ export function useDroppable({ dropTargetId, group = defaultDroppableGroup, containerId = null, }) {
6
+ const context = useContext(DragContext);
7
+ if (!context) {
8
+ throw new Error("useDroppable must be used inside DragProvider");
9
+ }
10
+ const { runtime } = context;
11
+ const behavior = useMemo(() => createDomDroppable({
12
+ runtime,
13
+ dropTargetId,
14
+ group,
15
+ containerId,
16
+ }), [containerId, dropTargetId, group, runtime]);
17
+ const setNodeRef = useCallback((node) => {
18
+ behavior.setElement(node);
19
+ }, [behavior]);
20
+ return useMemo(() => ({
21
+ ref: setNodeRef,
22
+ }), [setNodeRef]);
23
+ }
@@ -0,0 +1,2 @@
1
+ import type { RemeasureDropTargetsInput } from "@mk-drag-and-drop/dom";
2
+ export declare function useRemeasureDropTargets(): (input?: RemeasureDropTargetsInput) => void;
@@ -0,0 +1,12 @@
1
+ import { useCallback, useContext } from "react";
2
+ import { DragContext } from "../drag-context.js";
3
+ export function useRemeasureDropTargets() {
4
+ const context = useContext(DragContext);
5
+ if (!context) {
6
+ throw new Error("useRemeasureDropTargets must be used inside DragProvider");
7
+ }
8
+ const { runtime } = context;
9
+ return useCallback((input) => {
10
+ runtime.remeasureDropTargets(input);
11
+ }, [runtime]);
12
+ }
@@ -0,0 +1,13 @@
1
+ import { type HTMLAttributes, type RefCallback } from "react";
2
+ import { type SortableAxis, type SortablePlacementBoundary } from "@mk-drag-and-drop/dom/integration";
3
+ export type UseSortableOptions = {
4
+ draggableId: string;
5
+ group?: string;
6
+ containerId?: string | null;
7
+ axis?: SortableAxis;
8
+ placementBoundary?: SortablePlacementBoundary;
9
+ };
10
+ export type UseSortableResult<ElementType extends HTMLElement = HTMLElement> = HTMLAttributes<ElementType> & {
11
+ ref: RefCallback<ElementType>;
12
+ };
13
+ export declare function useSortable<ElementType extends HTMLElement = HTMLElement>({ draggableId, group, containerId, axis, placementBoundary, }: UseSortableOptions): UseSortableResult<ElementType>;
@@ -0,0 +1,49 @@
1
+ import { useCallback, useContext, useMemo, useRef, } from "react";
2
+ import { createDomSortable, } from "@mk-drag-and-drop/dom/integration";
3
+ import { DragContext } from "../drag-context.js";
4
+ const defaultSortableGroup = "default";
5
+ export function useSortable({ draggableId, group = defaultSortableGroup, containerId = null, axis, placementBoundary, }) {
6
+ const context = useContext(DragContext);
7
+ const nodeRef = useRef(null);
8
+ if (!context) {
9
+ throw new Error("useSortable must be used inside DragProvider");
10
+ }
11
+ const { runtime, keyboardDragEnabled } = context;
12
+ const getElement = useCallback(() => nodeRef.current, []);
13
+ const behavior = useMemo(() => createDomSortable({
14
+ runtime,
15
+ draggableId,
16
+ group,
17
+ containerId,
18
+ axis,
19
+ placementBoundary,
20
+ getElement,
21
+ keyboardDragEnabled,
22
+ }), [
23
+ axis,
24
+ containerId,
25
+ getElement,
26
+ group,
27
+ draggableId,
28
+ keyboardDragEnabled,
29
+ placementBoundary,
30
+ runtime,
31
+ ]);
32
+ const setNodeRef = useCallback((node) => {
33
+ nodeRef.current = node;
34
+ behavior.setElement(node);
35
+ }, [behavior]);
36
+ return useMemo(() => {
37
+ const sortableProps = {
38
+ ref: setNodeRef,
39
+ onPointerDown: behavior.onPointerDown,
40
+ };
41
+ return behavior.tabIndex === undefined
42
+ ? sortableProps
43
+ : {
44
+ ...sortableProps,
45
+ tabIndex: behavior.tabIndex,
46
+ onKeyDown: behavior.onKeyDown,
47
+ };
48
+ }, [behavior, setNodeRef]);
49
+ }
@@ -0,0 +1,12 @@
1
+ export { DragProvider, type DragAnnouncements, type DragProviderProps, } from "./drag-provider.js";
2
+ export type { DragOverlayInput } from "./drag-overlay.js";
3
+ export { centerToCenter, getDistanceToRect, lockToXAxis, lockToYAxis, maxOverlayCenterDistanceToRect, maxPointerDistanceToRect, pointerToCenter, pointerToRectDistance, type DragEndResult, type DragEndEvent, type DragLifecycleCallbacks, type DragLifecycleHelpers, type DragModifier, type DragModifierInput, type DragModifierSetupInput, type DragModifierTransformInput, type DragPoint, type DragRect, type DragSource, type DragStartEvent, type DragUpdateEvent, type DropEvent, type DropTarget, type KeyboardCommand, type KeyboardConfiguration, type PointerConfiguration, type RemeasureDropTargetsInput, type SortableAxis, type SortableDropPlacement, type SortablePlacementBoundary, type TargetingAlgorithm, type TargetingAlgorithmInput, type TargetingConstraint, type TargetingConstraintInput, } from "@mk-drag-and-drop/dom";
4
+ export { restrictToContainer, type ReactRestrictToContainerInput, } from "./modifiers/restrict-to-container.js";
5
+ export type { DragOverlayPhase, DragState, } from "@mk-drag-and-drop/dom/integration";
6
+ export { useDragHandle, type UseDragHandleResult, } from "./hooks/use-drag-handle.js";
7
+ export { useDraggable, type UseDraggableOptions, type UseDraggableResult, } from "./hooks/use-draggable.js";
8
+ export { useDropContainer, type UseDropContainerOptions, type UseDropContainerResult, } from "./hooks/use-drop-container.js";
9
+ export { useDroppable, type UseDroppableOptions, type UseDroppableResult, } from "./hooks/use-droppable.js";
10
+ export { useRemeasureDropTargets } from "./hooks/use-remeasure-drop-targets.js";
11
+ export { useSortable, type UseSortableOptions, type UseSortableResult, } from "./hooks/use-sortable.js";
12
+ export { composeRefs } from "./utils/compose-refs.js";
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { DragProvider, } from "./drag-provider.js";
2
+ export { centerToCenter, getDistanceToRect, lockToXAxis, lockToYAxis, maxOverlayCenterDistanceToRect, maxPointerDistanceToRect, pointerToCenter, pointerToRectDistance, } from "@mk-drag-and-drop/dom";
3
+ export { restrictToContainer, } from "./modifiers/restrict-to-container.js";
4
+ export { useDragHandle, } from "./hooks/use-drag-handle.js";
5
+ export { useDraggable, } from "./hooks/use-draggable.js";
6
+ export { useDropContainer, } from "./hooks/use-drop-container.js";
7
+ export { useDroppable, } from "./hooks/use-droppable.js";
8
+ export { useRemeasureDropTargets } from "./hooks/use-remeasure-drop-targets.js";
9
+ export { useSortable, } from "./hooks/use-sortable.js";
10
+ export { composeRefs } from "./utils/compose-refs.js";