@os-design/use-drag 1.0.9 → 1.0.11

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.
Files changed (2) hide show
  1. package/package.json +12 -5
  2. package/src/index.ts +162 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@os-design/use-drag",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "license": "UNLICENSED",
5
5
  "repository": "git@gitlab.com:os-team/libs/os-design.git",
6
6
  "main": "dist/cjs/index.js",
@@ -14,7 +14,14 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "src",
19
+ "!**/*.test.ts",
20
+ "!**/*.test.tsx",
21
+ "!**/__tests__",
22
+ "!**/*.stories.tsx",
23
+ "!**/*.stories.mdx",
24
+ "!**/*.example.tsx"
18
25
  ],
19
26
  "sideEffects": false,
20
27
  "scripts": {
@@ -29,11 +36,11 @@
29
36
  "access": "public"
30
37
  },
31
38
  "dependencies": {
32
- "@os-design/use-event": "^1.0.13",
33
- "@os-design/use-long-press": "^1.0.9"
39
+ "@os-design/use-event": "^1.0.15",
40
+ "@os-design/use-long-press": "^1.0.11"
34
41
  },
35
42
  "peerDependencies": {
36
43
  "react": ">=18"
37
44
  },
38
- "gitHead": "0e88d3afc41e36cee61222a039ef1aa4d08115b5"
45
+ "gitHead": "e5d8409760608145d2c738aa5789d0465ae5416f"
39
46
  }
package/src/index.ts ADDED
@@ -0,0 +1,162 @@
1
+ import useEvent from '@os-design/use-event';
2
+ import useLongPress from '@os-design/use-long-press';
3
+ import {
4
+ MouseEventHandler,
5
+ TouchEventHandler,
6
+ useCallback,
7
+ useEffect,
8
+ useRef,
9
+ } from 'react';
10
+
11
+ export interface Position {
12
+ x: number;
13
+ y: number;
14
+ }
15
+
16
+ export type OnDragStart = (position: Position, startPosition: Position) => void;
17
+ export type OnDragMove = (position: Position) => void;
18
+ export type OnDragEnd = () => void;
19
+
20
+ export interface UseDragProps {
21
+ minMouseDistPx?: number;
22
+ longPressMs?: number;
23
+ onDragStart?: OnDragStart;
24
+ onDragMove?: OnDragMove;
25
+ onDragEnd?: OnDragEnd;
26
+ }
27
+
28
+ const userSelection = {
29
+ disable: () => {
30
+ document.body.style.userSelect = 'none';
31
+ },
32
+ enable: () => {
33
+ document.body.style.userSelect = '';
34
+ },
35
+ };
36
+
37
+ export interface DragHandlers {
38
+ onMouseDown: MouseEventHandler;
39
+ onTouchStart: TouchEventHandler;
40
+ }
41
+
42
+ const useDrag = (props: UseDragProps): DragHandlers => {
43
+ const { minMouseDistPx = 10, longPressMs = 500 } = props;
44
+
45
+ const isDraggingRef = useRef(false);
46
+ const startMousePosRef = useRef<Position | null>(null);
47
+ const minMouseDistPxRef = useRef(minMouseDistPx);
48
+ const handlersRef = useRef({
49
+ onDragStart: props.onDragStart || (() => {}),
50
+ onDragMove: props.onDragMove || (() => {}),
51
+ onDragEnd: props.onDragEnd || (() => {}),
52
+ });
53
+
54
+ useEffect(() => {
55
+ minMouseDistPxRef.current = minMouseDistPx;
56
+ }, [minMouseDistPx]);
57
+
58
+ useEffect(() => {
59
+ handlersRef.current = {
60
+ onDragStart: props.onDragStart || (() => {}),
61
+ onDragMove: props.onDragMove || (() => {}),
62
+ onDragEnd: props.onDragEnd || (() => {}),
63
+ };
64
+ }, [props.onDragEnd, props.onDragMove, props.onDragStart]);
65
+
66
+ const dragStartHandler = useCallback(
67
+ (position: Position, startPosition: Position) => {
68
+ const { onDragStart } = handlersRef.current;
69
+ onDragStart(position, startPosition);
70
+ isDraggingRef.current = true;
71
+ startMousePosRef.current = null;
72
+ },
73
+ []
74
+ );
75
+
76
+ const dragEndHandler = useCallback(() => {
77
+ const { onDragEnd } = handlersRef.current;
78
+ if (isDraggingRef.current) onDragEnd();
79
+ isDraggingRef.current = false;
80
+ startMousePosRef.current = null;
81
+ userSelection.enable();
82
+ }, []);
83
+
84
+ const onMouseDown = useCallback<MouseEventHandler>((e) => {
85
+ if (e.button !== 0) return; // Allow only the left mouse button
86
+ startMousePosRef.current = { x: e.clientX, y: e.clientY };
87
+ userSelection.disable();
88
+ }, []);
89
+
90
+ const onMouseMove = useCallback(
91
+ (e: MouseEvent) => {
92
+ const pos = { x: e.clientX, y: e.clientY };
93
+ if (isDraggingRef.current) {
94
+ const { onDragMove } = handlersRef.current;
95
+ onDragMove(pos);
96
+ return;
97
+ }
98
+ const startPos = startMousePosRef.current;
99
+ if (!startPos) return;
100
+ const diffX = Math.abs(pos.x - startPos.x);
101
+ const diffY = Math.abs(pos.y - startPos.y);
102
+ const diff = Math.sqrt(diffX ** 2 + diffY ** 2);
103
+ if (diff >= minMouseDistPxRef.current) {
104
+ dragStartHandler(pos, startPos);
105
+ }
106
+ },
107
+ [dragStartHandler]
108
+ );
109
+
110
+ const onMouseUp = useCallback(() => {
111
+ dragEndHandler();
112
+ }, [dragEndHandler]);
113
+
114
+ const longPressHandler = useCallback<TouchEventHandler>(
115
+ (e) => {
116
+ if (e.touches.length === 0) return;
117
+ const pos = { x: e.touches[0].clientX, y: e.touches[0].clientY };
118
+ dragStartHandler(pos, pos);
119
+ },
120
+ [dragStartHandler]
121
+ );
122
+
123
+ const { onTouchStart, onTouchMove, onTouchEnd } = useLongPress(
124
+ longPressHandler,
125
+ longPressMs
126
+ );
127
+
128
+ const touchStartHandler = useCallback<TouchEventHandler>(
129
+ (e) => {
130
+ onTouchStart(e);
131
+ userSelection.disable();
132
+ },
133
+ [onTouchStart]
134
+ );
135
+
136
+ const touchMoveHandler = useCallback(
137
+ (e: TouchEvent) => {
138
+ onTouchMove();
139
+ if (!isDraggingRef.current || e.touches.length === 0) return;
140
+ const { onDragMove } = handlersRef.current;
141
+ onDragMove({ x: e.touches[0].clientX, y: e.touches[0].clientY });
142
+ },
143
+ [onTouchMove]
144
+ );
145
+
146
+ const touchEndHandler = useCallback(() => {
147
+ onTouchEnd();
148
+ dragEndHandler();
149
+ }, [dragEndHandler, onTouchEnd]);
150
+
151
+ useEvent(document, 'mousemove', onMouseMove);
152
+ useEvent(document, 'mouseup', onMouseUp);
153
+ useEvent(document, 'touchmove', touchMoveHandler);
154
+ useEvent(document, 'touchend', touchEndHandler);
155
+
156
+ return {
157
+ onMouseDown,
158
+ onTouchStart: touchStartHandler,
159
+ };
160
+ };
161
+
162
+ export default useDrag;