react-reorder-list 0.5.0 → 0.6.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,6 @@
1
+ import { DetailedHTMLProps, HTMLAttributes } from "react";
2
+ export type Props = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
3
+ export default function useDraggable(initValue?: boolean): {
4
+ draggable: boolean;
5
+ draggableProps: Props;
6
+ };
package/dist/hooks.js ADDED
@@ -0,0 +1,8 @@
1
+ import { useState } from "react";
2
+ export default function useDraggable(initValue = false) {
3
+ const [draggable, setDraggable] = useState(initValue);
4
+ const enableDragging = () => setDraggable(true);
5
+ const disableDragging = () => setDraggable(false);
6
+ const draggableProps = { onMouseEnter: enableDragging, onMouseLeave: disableDragging, onTouchStart: enableDragging, onTouchEnd: disableDragging };
7
+ return { draggable, draggableProps };
8
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import React, { DetailedHTMLProps, HTMLAttributes, ReactNode } from "react";
2
- export type Props = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
1
+ import React, { ReactNode } from "react";
2
+ import { Props } from "./hooks.js";
3
+ export type { Props } from './hooks.js';
3
4
  export type PositionChangeHandler = (params?: {
4
5
  start?: number;
5
6
  end?: number;
package/dist/index.js CHANGED
@@ -12,6 +12,10 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import React, { Children, cloneElement, createRef, forwardRef, isValidElement, useEffect, useMemo, useRef, useState } from "react";
13
13
  import { PiDotsSixVerticalBold } from "./icons.js";
14
14
  import Animation from "./animation.js";
15
+ import useDraggable from "./hooks.js";
16
+ if (typeof window !== "undefined")
17
+ import('drag-drop-touch');
18
+ const scrollThreshold = { x: 10, y: 100 };
15
19
  const ReorderItemRef = forwardRef(ReorderItem);
16
20
  export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpacity = 0.5, animationDuration = 400, watchChildrenUpdates = false, preserveOrder = false, onPositionChange, disabled = false, props, children }) {
17
21
  const ref = useRef(null);
@@ -20,13 +24,14 @@ export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpa
20
24
  const [items, setItems] = useState(Children.toArray(children));
21
25
  const [temp, setTemp] = useState({});
22
26
  const [isAnimating, setIsAnimating] = useState(false);
27
+ const [scroll, setScroll] = useState();
23
28
  const refs = useMemo(() => items.map(_ => createRef()), [items]);
24
29
  const findIndex = (key) => key ? items.findIndex(item => { var _a, _b; return ((_b = (_a = item === null || item === void 0 ? void 0 : item.key) === null || _a === void 0 ? void 0 : _a.split(".$").at(-1)) !== null && _b !== void 0 ? _b : item === null || item === void 0 ? void 0 : item.toString()) === key; }) : -1;
25
30
  useEffect(() => {
26
31
  if (!watchChildrenUpdates)
27
32
  return;
28
33
  if (selected !== -1)
29
- handleDragEnd(selected, preserveOrder);
34
+ handleDragEnd(null, selected, preserveOrder);
30
35
  if (preserveOrder) {
31
36
  const items = [];
32
37
  const newItems = [];
@@ -43,15 +48,27 @@ export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpa
43
48
  else
44
49
  setItems(Children.toArray(children));
45
50
  }, [children]);
46
- function handleDragEnd(end, handlePositionChange = true) {
51
+ useEffect(() => {
52
+ if (!scroll)
53
+ return;
54
+ const { left, top } = scroll;
55
+ const { scrollWidth, scrollHeight } = document.body;
56
+ const interval = setInterval(() => {
57
+ if (left < 0 || top < 0 || scrollWidth - scrollX > innerWidth - left || scrollHeight - scrollY > innerHeight - top)
58
+ scrollBy({ left, top, behavior: 'instant' });
59
+ }, 20);
60
+ return () => clearInterval(interval);
61
+ }, [scroll]);
62
+ function handleDragEnd(event, end = selected, handlePositionChange = true) {
63
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
47
64
  if (handlePositionChange && end !== start)
48
65
  onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange({ start, end, oldItems: temp.items, newItems: items, revert: () => setItems(temp.items) });
49
66
  setStart(-1);
50
67
  setSelected(-1);
51
68
  }
52
- return React.createElement("div", Object.assign({ ref: ref }, props), disabled ? children : React.createElement(Animation, { duration: +(start !== -1) && animationDuration }, Children.map(items, (child, i) => {
69
+ return React.createElement("div", Object.assign({ ref: ref }, props), disabled ? children : React.createElement(Animation, { duration: +(start !== -1 && !scroll) && animationDuration }, Children.map(items, (child, i) => {
53
70
  var _a;
54
- return React.createElement(ReorderItemRef, { key: (_a = child === null || child === void 0 ? void 0 : child.key) !== null && _a !== void 0 ? _a : child === null || child === void 0 ? void 0 : child.toString(), ref: refs[i], useOnlyIconToDrag: useOnlyIconToDrag, style: { opacity: selected === i ? selectedItemOpacity : 1 }, onDragStart: event => {
71
+ return React.createElement(ReorderItemRef, { key: (_a = child === null || child === void 0 ? void 0 : child.key) !== null && _a !== void 0 ? _a : child === null || child === void 0 ? void 0 : child.toString(), ref: refs[i], useOnlyIconToDrag: useOnlyIconToDrag, style: { opacity: selected === i ? selectedItemOpacity : 1, touchAction: "pan-y" }, onDragStart: event => {
55
72
  event.stopPropagation();
56
73
  setStart(i);
57
74
  setSelected(i);
@@ -61,7 +78,7 @@ export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpa
61
78
  if (start === -1 || selected === i || isAnimating)
62
79
  return;
63
80
  const { width: startWidth, height: startHeight } = temp.rect;
64
- const { left, top, width, height } = event.currentTarget.getBoundingClientRect();
81
+ const { left, top, width, height } = event.target.getBoundingClientRect();
65
82
  if (event.clientX - left > Math.min(startWidth, width) || event.clientY - top > Math.min(startHeight, height))
66
83
  return;
67
84
  setSelected(i);
@@ -72,27 +89,34 @@ export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpa
72
89
  });
73
90
  setIsAnimating(true);
74
91
  setTimeout(() => setIsAnimating(false), animationDuration);
75
- }, onDragEnd: event => {
76
- event.stopPropagation();
77
- handleDragEnd(i);
78
- } }, child);
92
+ }, onDragEnd: handleDragEnd, onTouchMove: event => {
93
+ const { clientX, screenX, clientY, screenY } = event.touches[0];
94
+ let left = 0, top = 0;
95
+ if (clientX < scrollThreshold.x)
96
+ left = -5;
97
+ else if (innerWidth - screenX < scrollThreshold.x)
98
+ left = 5;
99
+ if (clientY < scrollThreshold.y)
100
+ top = -10;
101
+ else if (innerHeight - screenY < scrollThreshold.y)
102
+ top = 10;
103
+ setScroll((left || top) ? { left, top } : undefined);
104
+ }, onTouchEnd: () => setScroll(undefined) }, child);
79
105
  })));
80
106
  }
81
- function ReorderItem({ useOnlyIconToDrag, style, onDragStart, onDragEnter, onDragEnd, children }, ref) {
82
- const [draggable, setDraggable] = useState(false);
83
- const onPointerEnter = () => setDraggable(true);
84
- const onPointerLeave = () => setDraggable(false);
85
- let props = { draggable, onDragStart, onDragEnter, onDragEnd };
86
- if (!useOnlyIconToDrag)
87
- props = Object.assign(Object.assign({}, props), { onPointerEnter, onPointerLeave });
107
+ function ReorderItem(_a, ref) {
108
+ var { useOnlyIconToDrag, onTouchEnd: propOnTouchEnd, children } = _a, props = __rest(_a, ["useOnlyIconToDrag", "onTouchEnd", "children"]);
109
+ const _b = useDraggable(), { draggable } = _b, _c = _b.draggableProps, { onTouchEnd: draggableOnTouchEnd } = _c, draggableProps = __rest(_c, ["onTouchEnd"]);
88
110
  const recursiveClone = (children) => Children.map(children, child => {
89
111
  if (!isValidElement(child))
90
112
  return child;
91
- const childProps = child.type === ReorderIcon ? { onPointerEnter, onPointerLeave } : {};
92
- return cloneElement(child, Object.assign({ children: recursiveClone(child.props.children) }, childProps));
113
+ return cloneElement(child, Object.assign({ children: recursiveClone(child.props.children) }, (child.type === ReorderIcon && draggableProps)));
93
114
  });
94
115
  const recursiveChildren = useMemo(() => useOnlyIconToDrag ? recursiveClone(children) : children, [children]);
95
- return React.createElement("div", Object.assign({ ref: ref, style: style }, props), recursiveChildren);
116
+ return React.createElement("div", Object.assign({ ref: ref, draggable: draggable }, props, (!useOnlyIconToDrag && draggableProps), { onTouchEnd: event => {
117
+ draggableOnTouchEnd(event);
118
+ propOnTouchEnd(event);
119
+ } }), recursiveChildren);
96
120
  }
97
121
  export function ReorderIcon(_a) {
98
122
  var { children = React.createElement(PiDotsSixVerticalBold, null), style } = _a, props = __rest(_a, ["children", "style"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-reorder-list",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "A simple react component that facilitates the reordering of JSX/HTML elements through drag-and-drop functionality, allowing for easy position changes.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,6 +32,9 @@
32
32
  "devDependencies": {
33
33
  "@types/react": "^18.2.48"
34
34
  },
35
+ "dependencies": {
36
+ "drag-drop-touch": "^1.3.1"
37
+ },
35
38
  "scripts": {
36
39
  "build": "pnpm i && tsc"
37
40
  }