@dnd-kit/react 0.0.8-beta-20250203004551 → 0.0.8-beta-20250203132449

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/hooks.cjs CHANGED
@@ -14,29 +14,38 @@ function useConstant(initializer) {
14
14
  }
15
15
  var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
16
16
  var useIsomorphicLayoutEffect = canUseDOM ? react.useLayoutEffect : react.useEffect;
17
+ function useForceUpdate() {
18
+ const setState = react.useState(0)[1];
19
+ return react.useCallback(() => {
20
+ setState((value) => value + 1);
21
+ }, [setState]);
22
+ }
17
23
 
18
24
  // src/hooks/useSignal.ts
19
25
  function useSignal(signal, sync = false) {
20
- let val = signal.peek();
26
+ const previous = react.useRef(signal.peek());
21
27
  const read = react.useRef(false);
22
- const update = react.useState(val)[1];
28
+ const forceUpdate = useForceUpdate();
23
29
  useIsomorphicLayoutEffect(
24
30
  () => state.effect(() => {
25
- if (val !== (val = signal.value)) {
31
+ const previousValue = previous.current;
32
+ const currentValue2 = signal.value;
33
+ if (previousValue !== currentValue2) {
34
+ previous.current = currentValue2;
26
35
  if (!read.current) return;
27
36
  if (sync) {
28
- reactDom.flushSync(() => update(val));
37
+ reactDom.flushSync(forceUpdate);
29
38
  } else {
30
- update(val);
39
+ forceUpdate();
31
40
  }
32
41
  }
33
42
  }),
34
- [signal, sync]
43
+ [signal, sync, forceUpdate]
35
44
  );
36
45
  return {
37
46
  get value() {
38
47
  read.current = true;
39
- return signal.value;
48
+ return signal.peek();
40
49
  }
41
50
  };
42
51
  }
@@ -50,6 +59,39 @@ function useComputed(compute, dependencies = [], sync = false) {
50
59
  sync
51
60
  );
52
61
  }
62
+ function useDeepSignal(target) {
63
+ const tracked = react.useRef(/* @__PURE__ */ new Map());
64
+ const forceUpdate = useForceUpdate();
65
+ useIsomorphicLayoutEffect(() => {
66
+ if (!target) {
67
+ tracked.current.clear();
68
+ return;
69
+ }
70
+ return state.effect(() => {
71
+ let stale = false;
72
+ for (const entry of tracked.current) {
73
+ const [key] = entry;
74
+ const value = state.untracked(() => entry[1]);
75
+ const latestValue = target[key];
76
+ if (value !== latestValue) {
77
+ stale = true;
78
+ tracked.current.set(key, latestValue);
79
+ }
80
+ }
81
+ if (stale) forceUpdate();
82
+ });
83
+ }, [target]);
84
+ return react.useMemo(
85
+ () => target ? new Proxy(target, {
86
+ get(target2, key) {
87
+ const value = target2[key];
88
+ tracked.current.set(key, value);
89
+ return value;
90
+ }
91
+ }) : target,
92
+ [target]
93
+ );
94
+ }
53
95
 
54
96
  // src/hooks/useImmediateEffect.ts
55
97
  function useImmediateEffect(callback, _) {
@@ -62,9 +104,9 @@ function useLatest(value) {
62
104
  }, [value]);
63
105
  return valueRef;
64
106
  }
65
- function useOnValueChange(value, onChange, effect2 = react.useEffect, compare = Object.is) {
107
+ function useOnValueChange(value, onChange, effect3 = react.useEffect, compare = Object.is) {
66
108
  const tracked = react.useRef(value);
67
- effect2(() => {
109
+ effect3(() => {
68
110
  const oldValue = tracked.current;
69
111
  if (!compare(value, oldValue)) {
70
112
  tracked.current = value;
@@ -85,6 +127,7 @@ function useOnElementChange(value, onChange) {
85
127
 
86
128
  exports.useComputed = useComputed;
87
129
  exports.useConstant = useConstant;
130
+ exports.useDeepSignal = useDeepSignal;
88
131
  exports.useImmediateEffect = useImmediateEffect;
89
132
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
90
133
  exports.useLatest = useLatest;
package/hooks.d.ts CHANGED
@@ -8,6 +8,9 @@ declare function useComputed<T = any>(compute: () => T, dependencies?: any[], sy
8
8
  readonly value: T;
9
9
  };
10
10
 
11
+ /** Trigger a re-render when reading signal properties of an object. */
12
+ declare function useDeepSignal<T extends object | null | undefined>(target: T): T;
13
+
11
14
  declare function useImmediateEffect(callback: EffectCallback, _?: DependencyList): void;
12
15
 
13
16
  /**
@@ -22,4 +25,4 @@ declare function useOnValueChange<T>(value: T, onChange: (value: T, oldValue: T)
22
25
 
23
26
  declare function useOnElementChange(value: RefOrValue<Element>, onChange: (value: Element | undefined) => void): void;
24
27
 
25
- export { useComputed, useConstant, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnElementChange, useOnValueChange };
28
+ export { useComputed, useConstant, useDeepSignal, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnElementChange, useOnValueChange };
package/hooks.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useRef, useLayoutEffect, useEffect, useMemo, useState } from 'react';
2
- import { computed, effect } from '@dnd-kit/state';
1
+ import { useRef, useLayoutEffect, useEffect, useMemo, useState, useCallback } from 'react';
2
+ import { computed, effect, untracked } from '@dnd-kit/state';
3
3
  import { flushSync } from 'react-dom';
4
4
  import { currentValue } from '@dnd-kit/react/utilities';
5
5
 
@@ -12,29 +12,38 @@ function useConstant(initializer) {
12
12
  }
13
13
  var canUseDOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
14
14
  var useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
15
+ function useForceUpdate() {
16
+ const setState = useState(0)[1];
17
+ return useCallback(() => {
18
+ setState((value) => value + 1);
19
+ }, [setState]);
20
+ }
15
21
 
16
22
  // src/hooks/useSignal.ts
17
23
  function useSignal(signal, sync = false) {
18
- let val = signal.peek();
24
+ const previous = useRef(signal.peek());
19
25
  const read = useRef(false);
20
- const update = useState(val)[1];
26
+ const forceUpdate = useForceUpdate();
21
27
  useIsomorphicLayoutEffect(
22
28
  () => effect(() => {
23
- if (val !== (val = signal.value)) {
29
+ const previousValue = previous.current;
30
+ const currentValue2 = signal.value;
31
+ if (previousValue !== currentValue2) {
32
+ previous.current = currentValue2;
24
33
  if (!read.current) return;
25
34
  if (sync) {
26
- flushSync(() => update(val));
35
+ flushSync(forceUpdate);
27
36
  } else {
28
- update(val);
37
+ forceUpdate();
29
38
  }
30
39
  }
31
40
  }),
32
- [signal, sync]
41
+ [signal, sync, forceUpdate]
33
42
  );
34
43
  return {
35
44
  get value() {
36
45
  read.current = true;
37
- return signal.value;
46
+ return signal.peek();
38
47
  }
39
48
  };
40
49
  }
@@ -48,6 +57,39 @@ function useComputed(compute, dependencies = [], sync = false) {
48
57
  sync
49
58
  );
50
59
  }
60
+ function useDeepSignal(target) {
61
+ const tracked = useRef(/* @__PURE__ */ new Map());
62
+ const forceUpdate = useForceUpdate();
63
+ useIsomorphicLayoutEffect(() => {
64
+ if (!target) {
65
+ tracked.current.clear();
66
+ return;
67
+ }
68
+ return effect(() => {
69
+ let stale = false;
70
+ for (const entry of tracked.current) {
71
+ const [key] = entry;
72
+ const value = untracked(() => entry[1]);
73
+ const latestValue = target[key];
74
+ if (value !== latestValue) {
75
+ stale = true;
76
+ tracked.current.set(key, latestValue);
77
+ }
78
+ }
79
+ if (stale) forceUpdate();
80
+ });
81
+ }, [target]);
82
+ return useMemo(
83
+ () => target ? new Proxy(target, {
84
+ get(target2, key) {
85
+ const value = target2[key];
86
+ tracked.current.set(key, value);
87
+ return value;
88
+ }
89
+ }) : target,
90
+ [target]
91
+ );
92
+ }
51
93
 
52
94
  // src/hooks/useImmediateEffect.ts
53
95
  function useImmediateEffect(callback, _) {
@@ -60,9 +102,9 @@ function useLatest(value) {
60
102
  }, [value]);
61
103
  return valueRef;
62
104
  }
63
- function useOnValueChange(value, onChange, effect2 = useEffect, compare = Object.is) {
105
+ function useOnValueChange(value, onChange, effect3 = useEffect, compare = Object.is) {
64
106
  const tracked = useRef(value);
65
- effect2(() => {
107
+ effect3(() => {
66
108
  const oldValue = tracked.current;
67
109
  if (!compare(value, oldValue)) {
68
110
  tracked.current = value;
@@ -81,6 +123,6 @@ function useOnElementChange(value, onChange) {
81
123
  });
82
124
  }
83
125
 
84
- export { useComputed, useConstant, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnElementChange, useOnValueChange };
126
+ export { useComputed, useConstant, useDeepSignal, useImmediateEffect, useIsomorphicLayoutEffect, useLatest, useOnElementChange, useOnValueChange };
85
127
  //# sourceMappingURL=hooks.js.map
86
128
  //# sourceMappingURL=hooks.js.map
package/index.cjs CHANGED
@@ -245,6 +245,39 @@ function useDraggable(input) {
245
245
  )
246
246
  };
247
247
  }
248
+ function DragOverlay({ children, className }) {
249
+ const ref = react.useRef(null);
250
+ const manager = useDragDropManager();
251
+ const source = hooks.useComputed(
252
+ () => manager == null ? void 0 : manager.dragOperation.source,
253
+ [manager]
254
+ ).value;
255
+ react.useEffect(() => {
256
+ if (!ref.current || !manager) return;
257
+ const feedback = manager.plugins.find(
258
+ (plugin) => plugin instanceof dom.Feedback
259
+ );
260
+ if (!feedback) return;
261
+ feedback.overlay = ref.current;
262
+ return () => {
263
+ feedback.overlay = void 0;
264
+ };
265
+ }, [manager]);
266
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, ref, "data-dnd-overlay": true, children: renderChildren() });
267
+ function renderChildren() {
268
+ if (!source) return null;
269
+ if (typeof children === "function") {
270
+ return /* @__PURE__ */ jsxRuntime.jsx(Children, { source, children });
271
+ }
272
+ return children;
273
+ }
274
+ }
275
+ function Children({
276
+ children,
277
+ source
278
+ }) {
279
+ return children(hooks.useDeepSignal(source));
280
+ }
248
281
  function useDroppable(input) {
249
282
  const { collisionDetector, data, disabled, element, id, accept, type } = input;
250
283
  const droppable = useInstance(
@@ -295,6 +328,7 @@ function useDragOperation() {
295
328
  }
296
329
 
297
330
  exports.DragDropProvider = DragDropProvider;
331
+ exports.DragOverlay = DragOverlay;
298
332
  exports.useDragDropManager = useDragDropManager;
299
333
  exports.useDragOperation = useDragOperation;
300
334
  exports.useDraggable = useDraggable;
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PropsWithChildren } from 'react';
2
+ import { PropsWithChildren, ReactNode } from 'react';
3
3
  import * as _dnd_kit_abstract from '@dnd-kit/abstract';
4
4
  import { DragDropEvents, Data, DragDropManager as DragDropManager$1 } from '@dnd-kit/abstract';
5
5
  import * as _dnd_kit_dom from '@dnd-kit/dom';
@@ -8,7 +8,7 @@ import { RefOrValue } from '@dnd-kit/react/utilities';
8
8
  import { CleanupFunction } from '@dnd-kit/state';
9
9
 
10
10
  type Events = DragDropEvents<Draggable, Droppable, DragDropManager>;
11
- interface Props extends DragDropManagerInput, PropsWithChildren {
11
+ interface Props$1 extends DragDropManagerInput, PropsWithChildren {
12
12
  manager?: DragDropManager;
13
13
  onBeforeDragStart?: Events['beforedragstart'];
14
14
  onCollision?: Events['collision'];
@@ -17,7 +17,7 @@ interface Props extends DragDropManagerInput, PropsWithChildren {
17
17
  onDragOver?: Events['dragover'];
18
18
  onDragEnd?: Events['dragend'];
19
19
  }
20
- declare function DragDropProvider({ children, onCollision, onBeforeDragStart, onDragStart, onDragMove, onDragOver, onDragEnd, ...input }: Props): react_jsx_runtime.JSX.Element;
20
+ declare function DragDropProvider({ children, onCollision, onBeforeDragStart, onDragStart, onDragMove, onDragOver, onDragEnd, ...input }: Props$1): react_jsx_runtime.JSX.Element;
21
21
 
22
22
  interface UseDraggableInput<T extends Data = Data> extends Omit<DraggableInput<T>, 'handle' | 'element'> {
23
23
  handle?: RefOrValue<Element>;
@@ -31,6 +31,12 @@ declare function useDraggable<T extends Data = Data>(input: UseDraggableInput<T>
31
31
  ref: (element: Element | null) => void;
32
32
  };
33
33
 
34
+ interface Props {
35
+ className?: string;
36
+ children: ReactNode | ((source: Draggable) => ReactNode);
37
+ }
38
+ declare function DragOverlay({ children, className }: Props): react_jsx_runtime.JSX.Element;
39
+
34
40
  interface UseDroppableInput<T extends Data = Data> extends Omit<DroppableInput<T>, 'element'> {
35
41
  element?: RefOrValue<Element>;
36
42
  }
@@ -53,4 +59,4 @@ interface Instance<T extends DragDropManager$1<any, any> = DragDropManager$1<any
53
59
  }
54
60
  declare function useInstance<T extends Instance>(initializer: (manager: DragDropManager$1<any, any> | undefined) => T): T;
55
61
 
56
- export { DragDropProvider, type UseDraggableInput, type UseDroppableInput, useDragDropManager, useDragOperation, useDraggable, useDroppable, useInstance };
62
+ export { DragDropProvider, DragOverlay, type UseDraggableInput, type UseDroppableInput, useDragDropManager, useDragOperation, useDraggable, useDroppable, useInstance };
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { createContext, useState, useEffect, startTransition, useContext, useCallback, useTransition, useRef, useLayoutEffect } from 'react';
2
- import { DragDropManager, defaultPreset, Draggable, Droppable } from '@dnd-kit/dom';
3
- import { useLatest, useOnValueChange, useIsomorphicLayoutEffect, useComputed, useOnElementChange, useConstant } from '@dnd-kit/react/hooks';
1
+ import { createContext, useState, useEffect, startTransition, useContext, useCallback, useRef, useTransition, useLayoutEffect } from 'react';
2
+ import { DragDropManager, defaultPreset, Draggable, Feedback, Droppable } from '@dnd-kit/dom';
3
+ import { useLatest, useOnValueChange, useIsomorphicLayoutEffect, useComputed, useOnElementChange, useDeepSignal, useConstant } from '@dnd-kit/react/hooks';
4
4
  import { deepEqual } from '@dnd-kit/state';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import { currentValue } from '@dnd-kit/react/utilities';
@@ -243,6 +243,39 @@ function useDraggable(input) {
243
243
  )
244
244
  };
245
245
  }
246
+ function DragOverlay({ children, className }) {
247
+ const ref = useRef(null);
248
+ const manager = useDragDropManager();
249
+ const source = useComputed(
250
+ () => manager == null ? void 0 : manager.dragOperation.source,
251
+ [manager]
252
+ ).value;
253
+ useEffect(() => {
254
+ if (!ref.current || !manager) return;
255
+ const feedback = manager.plugins.find(
256
+ (plugin) => plugin instanceof Feedback
257
+ );
258
+ if (!feedback) return;
259
+ feedback.overlay = ref.current;
260
+ return () => {
261
+ feedback.overlay = void 0;
262
+ };
263
+ }, [manager]);
264
+ return /* @__PURE__ */ jsx("div", { className, ref, "data-dnd-overlay": true, children: renderChildren() });
265
+ function renderChildren() {
266
+ if (!source) return null;
267
+ if (typeof children === "function") {
268
+ return /* @__PURE__ */ jsx(Children, { source, children });
269
+ }
270
+ return children;
271
+ }
272
+ }
273
+ function Children({
274
+ children,
275
+ source
276
+ }) {
277
+ return children(useDeepSignal(source));
278
+ }
246
279
  function useDroppable(input) {
247
280
  const { collisionDetector, data, disabled, element, id, accept, type } = input;
248
281
  const droppable = useInstance(
@@ -292,6 +325,6 @@ function useDragOperation() {
292
325
  };
293
326
  }
294
327
 
295
- export { DragDropProvider, useDragDropManager, useDragOperation, useDraggable, useDroppable, useInstance };
328
+ export { DragDropProvider, DragOverlay, useDragDropManager, useDragOperation, useDraggable, useDroppable, useInstance };
296
329
  //# sourceMappingURL=index.js.map
297
330
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dnd-kit/react",
3
- "version": "0.0.8-beta-20250203004551",
3
+ "version": "0.0.8-beta-20250203132449",
4
4
  "main": "./index.cjs",
5
5
  "module": "./index.js",
6
6
  "type": "module",
@@ -56,9 +56,9 @@
56
56
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
57
57
  },
58
58
  "dependencies": {
59
- "@dnd-kit/abstract": "0.0.8-beta-20250203004551",
60
- "@dnd-kit/dom": "0.0.8-beta-20250203004551",
61
- "@dnd-kit/state": "0.0.8-beta-20250203004551",
59
+ "@dnd-kit/abstract": "0.0.8-beta-20250203132449",
60
+ "@dnd-kit/dom": "0.0.8-beta-20250203132449",
61
+ "@dnd-kit/state": "0.0.8-beta-20250203132449",
62
62
  "tslib": "^2.6.2"
63
63
  },
64
64
  "peerDependencies": {