react-reorder-list
Advanced tools
Comparing version 0.1.3 to 0.2.0
@@ -12,2 +12,3 @@ import React, { DetailedHTMLProps, HTMLAttributes, ReactNode } from 'react'; | ||
selectedItemOpacity?: number; | ||
animationDuration?: number; | ||
onPositionChange?: PositionChangeHandler; | ||
@@ -19,3 +20,3 @@ disable?: boolean; | ||
export type { IconProps } from './icons.js'; | ||
export default function ReorderList({ useOnlyIconToDrag, selectedItemOpacity, onPositionChange, disable, props, children }: ReorderListProps): React.JSX.Element; | ||
export default function ReorderList({ useOnlyIconToDrag, selectedItemOpacity, animationDuration, onPositionChange, disable, props, children }: ReorderListProps): React.JSX.Element; | ||
export declare const ReorderIcon: ({ children, style, ...props }: Props) => React.JSX.Element; |
@@ -12,53 +12,61 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
}; | ||
import React, { Children, cloneElement, isValidElement, useMemo, useState } from 'react'; | ||
import React, { Children, cloneElement, createRef, forwardRef, isValidElement, useMemo, useRef, useState } from 'react'; | ||
import { PiDotsSixVerticalBold } from './icons.js'; | ||
export default function ReorderList({ useOnlyIconToDrag = true, selectedItemOpacity = 0.5, onPositionChange, disable = false, props, children }) { | ||
import Animation from './animation.js'; | ||
const ReorderItem = forwardRef(({ useOnlyIconToDrag, draggable, style, onDragStart, onDragEnter, onDragEnd, onPointerEnter, onPointerLeave, children }, ref) => { | ||
const props = draggable ? { draggable, onDragStart, onDragEnter, onDragEnd } : {}; | ||
const recursiveClone = (children) => Children.map(children, child => { | ||
if (!isValidElement(child)) | ||
return child; | ||
const childProps = {}; | ||
if (useOnlyIconToDrag && child.type.name === 'ReorderIcon') { | ||
childProps.onPointerEnter = onPointerEnter; | ||
childProps.onPointerLeave = onPointerLeave; | ||
} | ||
return cloneElement(child, Object.assign({ children: recursiveClone(child.props.children) }, childProps)); | ||
}); | ||
const recursiveChildren = useMemo(() => recursiveClone(children), [children]); | ||
return React.createElement("div", Object.assign({ ref: ref, style: style }, props), recursiveChildren); | ||
}); | ||
export default function ReorderList({ useOnlyIconToDrag = false, selectedItemOpacity = 0.5, animationDuration = 400, onPositionChange, disable = false, props, children }) { | ||
const ref = useRef(); | ||
const [draggable, setDraggable] = useState(!useOnlyIconToDrag); | ||
const [start, setStart] = useState(-1); | ||
const [selected, setSelected] = useState(-1); | ||
const [items, setItems] = useState(children); | ||
const [temp, setTemp] = useState([]); | ||
return React.createElement("div", Object.assign({}, props), disable ? children : Children.map(items, (child, i) => { | ||
const [temp, setTemp] = useState({}); | ||
const [isAnimating, setIsAnimating] = useState(false); | ||
return React.createElement("div", Object.assign({ ref: ref }, props), disable ? children : React.createElement(Animation, { duration: +draggable && animationDuration }, Children.map(items, (child, i) => { | ||
if (!isValidElement(child)) | ||
return child; | ||
return React.createElement(ReorderItem, { key: child.key || i, opacity: selected === i ? selectedItemOpacity : 1, useOnlyIconToDrag: useOnlyIconToDrag, onDragStart: event => { | ||
return React.createElement(ReorderItem, { key: child.key || i, ref: createRef(), useOnlyIconToDrag: useOnlyIconToDrag, draggable: draggable, style: { opacity: selected === i ? selectedItemOpacity : 1 }, onDragStart: event => { | ||
event.stopPropagation(); | ||
setStart(i); | ||
setSelected(i); | ||
setTemp(items); | ||
setTemp({ items, rect: ref.current.children[i].getBoundingClientRect() }); | ||
}, onDragEnter: event => { | ||
event.stopPropagation(); | ||
if (start === -1) | ||
if (start === -1 || selected === i || isAnimating) | ||
return; | ||
const { width: startWidth, height: startHeight } = temp.rect; | ||
const { left, top, width, height } = event.currentTarget.getBoundingClientRect(); | ||
if (event.clientX - left > Math.min(startWidth, width) || event.clientY - top > Math.min(startHeight, height)) | ||
return; | ||
setSelected(i); | ||
setItems(() => { | ||
const items = temp.filter((_, i) => i !== start); | ||
items.splice(i, 0, temp[start]); | ||
const items = temp.items.filter((_, i) => i !== start); | ||
items.splice(i, 0, temp.items[start]); | ||
return items; | ||
}); | ||
setIsAnimating(true); | ||
setTimeout(() => setIsAnimating(false), animationDuration); | ||
}, onDragEnd: event => { | ||
event.stopPropagation(); | ||
if (i !== start) | ||
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange({ start, end: i, oldItems: temp, newItems: items }); | ||
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange({ start, end: i, oldItems: temp.items, newItems: items }); | ||
setStart(-1); | ||
setSelected(-1); | ||
} }, child); | ||
})); | ||
}, onPointerEnter: () => setDraggable(true), onPointerLeave: () => setDraggable(false) }, child); | ||
}))); | ||
} | ||
function ReorderItem({ useOnlyIconToDrag, opacity, onDragStart, onDragEnter, onDragEnd, children }) { | ||
const [draggable, setDraggable] = useState(!useOnlyIconToDrag); | ||
const recursiveChildren = useMemo(() => recursiveClone(children), [children]); | ||
function recursiveClone(children) { | ||
return Children.map(children, child => { | ||
if (!isValidElement(child)) | ||
return child; | ||
const childProps = {}; | ||
if (useOnlyIconToDrag && child.type.name === 'ReorderIcon') { | ||
childProps.onPointerEnter = () => setDraggable(true); | ||
childProps.onPointerLeave = () => setDraggable(false); | ||
} | ||
return cloneElement(child, Object.assign({ children: recursiveClone(child.props.children) }, childProps)); | ||
}); | ||
} | ||
return React.createElement("div", { draggable: draggable, onDragStart: onDragStart, onDragEnter: onDragEnter, onDragEnd: onDragEnd, style: { opacity } }, recursiveChildren); | ||
} | ||
export const ReorderIcon = (_a) => { | ||
@@ -65,0 +73,0 @@ var { children = React.createElement(PiDotsSixVerticalBold, null), style } = _a, props = __rest(_a, ["children", "style"]); |
{ | ||
"name": "react-reorder-list", | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"description": "A simple react component that facilitates the reordering of JSX/HTML elements through drag-and-drop functionality, allowing for easy position changes.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -34,3 +34,3 @@ # react-reorder-list | ||
export default function App() { | ||
return <ReorderList useOnlyIconToDrag={false}> | ||
return <ReorderList> | ||
{[0, 1, 2, 3, 4].map(i => { | ||
@@ -50,3 +50,3 @@ {/* Having a unique key is important */} | ||
export default function App() { | ||
return <ReorderList> | ||
return <ReorderList useOnlyIconToDrag={true}> | ||
{[0, 1, 2, 3, 4].map(i => { | ||
@@ -73,5 +73,4 @@ return <div key={i}> | ||
return <div key={i}> | ||
<ReorderIcon /> | ||
<span>{'Parent' + i}</span> | ||
<ReorderList> | ||
<ReorderList useOnlyIconToDrag={true}> | ||
{[0, 1, 2].map(j => { | ||
@@ -93,4 +92,5 @@ return <div key={j} style={{ paddingLeft: '16px' }}> | ||
| - | - | - | - | - | | ||
| `useOnlyIconToDrag` | `Boolean` | No | true | See [usage with ReorderIcon](#usage-with-reordericon) | | ||
| `useOnlyIconToDrag` | `Boolean` | No | false | See [usage with ReorderIcon](#usage-with-reordericon) | | ||
| `selectedItemOpacity` | `Number (0 to 1)` | No | 0.5 | This determines the opacity of the item being dragged, until released. | | ||
| `animationDuration` | `Number` | No | 400 | The duration of swapping animation between items. If set to 0, animation will be disabled. | | ||
| `onPositionChange` | [`PositionChangeHandler`](#positionchangehandler) | No | - | Function to be executed on item position change. | | ||
@@ -97,0 +97,0 @@ | `disable` | `Boolean` | No | false | When set to true, `ReorderList` will work as a plain `div` with no functionality. | |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14502
9
160