use-drag-controls.mjs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import { useConstant } from '../../utils/use-constant.mjs';
  2. /**
  3. * Can manually trigger a drag gesture on one or more `drag`-enabled `motion` components.
  4. *
  5. * ```jsx
  6. * const dragControls = useDragControls()
  7. *
  8. * function startDrag(event) {
  9. * dragControls.start(event, { snapToCursor: true })
  10. * }
  11. *
  12. * return (
  13. * <>
  14. * <div onPointerDown={startDrag} />
  15. * <motion.div drag="x" dragControls={dragControls} />
  16. * </>
  17. * )
  18. * ```
  19. *
  20. * @public
  21. */
  22. class DragControls {
  23. constructor() {
  24. this.componentControls = new Set();
  25. }
  26. /**
  27. * Subscribe a component's internal `VisualElementDragControls` to the user-facing API.
  28. *
  29. * @internal
  30. */
  31. subscribe(controls) {
  32. this.componentControls.add(controls);
  33. return () => this.componentControls.delete(controls);
  34. }
  35. /**
  36. * Start a drag gesture on every `motion` component that has this set of drag controls
  37. * passed into it via the `dragControls` prop.
  38. *
  39. * ```jsx
  40. * dragControls.start(e, {
  41. * snapToCursor: true
  42. * })
  43. * ```
  44. *
  45. * @param event - PointerEvent
  46. * @param options - Options
  47. *
  48. * @public
  49. */
  50. start(event, options) {
  51. this.componentControls.forEach((controls) => {
  52. controls.start(event.nativeEvent || event, options);
  53. });
  54. }
  55. }
  56. const createDragControls = () => new DragControls();
  57. /**
  58. * Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop
  59. * and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we
  60. * might want to initiate that dragging from a different component than the draggable one.
  61. *
  62. * By creating a `dragControls` using the `useDragControls` hook, we can pass this into
  63. * the draggable component's `dragControls` prop. It exposes a `start` method
  64. * that can start dragging from pointer events on other components.
  65. *
  66. * ```jsx
  67. * const dragControls = useDragControls()
  68. *
  69. * function startDrag(event) {
  70. * dragControls.start(event, { snapToCursor: true })
  71. * }
  72. *
  73. * return (
  74. * <>
  75. * <div onPointerDown={startDrag} />
  76. * <motion.div drag="x" dragControls={dragControls} />
  77. * </>
  78. * )
  79. * ```
  80. *
  81. * @public
  82. */
  83. function useDragControls() {
  84. return useConstant(createDragControls);
  85. }
  86. export { DragControls, useDragControls };