Skip to content

Commit 5363745

Browse files
tumisproThomas Moeskops
andauthored
feat: Sort start and move events + restore original element opacity (#51)
* Add new onSortStart and onSortMove props * Restore original opacity of dragged element (if set) * Update docs to add the new props * Tiny typo in docs update * Fix styles in docs update --------- Co-authored-by: Thomas Moeskops <t.moeskops@leads.io>
1 parent 0f57f5d commit 5363745

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,17 @@ const App = () => {
7272

7373
### SortableList
7474

75-
| Name | Description | Type | Default |
76-
| ------------------------ | :----------------------------------------------------------: | :--------------------------------------------: | --------------: |
77-
| **as** | Determines html tag for the container element | `keyof JSX.IntrinsicElements` | `div` |
78-
| **onSortEnd\*** | Called when the user finishes a sorting gesture. | `(oldIndex: number, newIndex: number) => void` | - |
79-
| **draggedItemClassName** | Class applied to the item being dragged | `string` | - |
80-
| **lockAxis** | Determines if an axis should be locked | `'x'` or `'y'` | |
81-
| **allowDrag** | Determines whether items can be dragged | `boolean` | `true` |
82-
| **customHolderRef** | Ref of an element to use as a container for the dragged item | `React.RefObject<HTMLElement \| null>` | `document.body` |
83-
| **dropTarget** | React element to use as a dropTarget | `ReactNode` | |
75+
| Name | Description | Type | Default |
76+
|--------------------------|:----------------------------------------------------------------------:|:----------------------------------------------:| --------------: |
77+
| **as** | Determines html tag for the container element | `keyof JSX.IntrinsicElements` | `div` |
78+
| **onSortStart** | Called when the user starts a sorting gesture | `() => void` | - |
79+
| **onSortMove** | Called when the dragged item changes position during a sorting gesture | `(newIndex: number) => void` | - |
80+
| **onSortEnd\*** | Called when the user finishes a sorting gesture. | `(oldIndex: number, newIndex: number) => void` | - |
81+
| **draggedItemClassName** | Class applied to the item being dragged | `string` | - |
82+
| **lockAxis** | Determines if an axis should be locked | `'x'` or `'y'` | |
83+
| **allowDrag** | Determines whether items can be dragged | `boolean` | `true` |
84+
| **customHolderRef** | Ref of an element to use as a container for the dragged item | `React.RefObject<HTMLElement \| null>` | `document.body` |
85+
| **dropTarget** | React element to use as a dropTarget | `ReactNode` | |
8486

8587
### SortableItem
8688

src/index.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ type Props<TTag extends keyof JSX.IntrinsicElements> = HTMLAttributes<TTag> & {
1111
children: React.ReactNode
1212
/** Determines whether drag functionality is enabled, defaults to true */
1313
allowDrag?: boolean
14+
/** Called when the user starts a sorting gesture. */
15+
onSortStart?: () => void
16+
/** Called when the position of an item changed during a sorting gesture. */
17+
onSortMove?: (newIndex: number) => void
1418
/** Called when the user finishes a sorting gesture. */
1519
onSortEnd: (oldIndex: number, newIndex: number) => void
1620
/** Class applied to the item being dragged */
@@ -38,6 +42,8 @@ const SortableListContext = React.createContext<Context | undefined>(undefined)
3842
const SortableList = <TTag extends keyof JSX.IntrinsicElements = typeof DEFAULT_CONTAINER_TAG>({
3943
children,
4044
allowDrag = true,
45+
onSortStart,
46+
onSortMove,
4147
onSortEnd,
4248
draggedItemClassName,
4349
as,
@@ -64,6 +70,8 @@ const SortableList = <TTag extends keyof JSX.IntrinsicElements = typeof DEFAULT_
6470
const offsetPointRef = React.useRef<Point>({ x: 0, y: 0 })
6571
// contains the dropTarget logic
6672
const dropTargetLogic = useDropTarget(dropTarget)
73+
// contains the original opacity of the sorted item in order te restore it correctly
74+
const sourceOpacityRef = React.useRef<string>('1')
6775

6876
React.useEffect(() => {
6977
const holder = customHolderRef?.current || document.body
@@ -146,11 +154,17 @@ const SortableList = <TTag extends keyof JSX.IntrinsicElements = typeof DEFAULT_
146154
// saving the index of the item being dragged
147155
sourceIndexRef.current = sourceIndex
148156

157+
// let the parent know that sort started
158+
if (onSortStart) {
159+
onSortStart();
160+
}
161+
149162
// the item being dragged is copied to the document body and will be used as the target
150163
copyItem(sourceIndex)
151164

152-
// hide source during the drag gesture
165+
// hide source during the drag gesture (and store original opacity)
153166
const source = itemsRef.current[sourceIndex]
167+
sourceOpacityRef.current = source.style.opacity ?? '1';
154168
source.style.opacity = '0'
155169
source.style.visibility = 'hidden'
156170

@@ -191,6 +205,12 @@ const SortableList = <TTag extends keyof JSX.IntrinsicElements = typeof DEFAULT_
191205
if (targetIndex === -1) {
192206
return
193207
}
208+
209+
// if targetIndex changed and last target index is set we can let the parent know the new position
210+
if (onSortMove && lastTargetIndexRef.current !== undefined && lastTargetIndexRef.current !== targetIndex) {
211+
onSortMove(targetIndex);
212+
}
213+
194214
// we keep track of the last target index (to be passed to the onSortEnd callback)
195215
lastTargetIndexRef.current = targetIndex
196216

@@ -237,7 +257,7 @@ const SortableList = <TTag extends keyof JSX.IntrinsicElements = typeof DEFAULT_
237257
// show the source item again
238258
const source = itemsRef.current[sourceIndex]
239259
if (source) {
240-
source.style.opacity = '1'
260+
source.style.opacity = sourceOpacityRef.current
241261
source.style.visibility = ''
242262
}
243263

0 commit comments

Comments
 (0)