diff --git a/.changeset/three-plants-bow.md b/.changeset/three-plants-bow.md new file mode 100644 index 0000000..b4828b8 --- /dev/null +++ b/.changeset/three-plants-bow.md @@ -0,0 +1,5 @@ +--- +"react-movable": minor +--- + +feat: implement afterDrag diff --git a/.gitignore b/.gitignore index 4a03db7..1970e09 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __diff_output__ /playwright-report/ /blob-report/ /playwright/.cache/ +/e2e/**/*.png \ No newline at end of file diff --git a/README.md b/README.md index 548c1bb..848fb11 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ An array of values. The value can be a string or any more complex object. The le ### onChange ```ts -onChange: (meta: { oldIndex: number; newIndex: number, targetRect: ClientRect }) => void +onChange: (meta: { oldIndex: number; newIndex: number, targetRect: DOMRect }) => void ``` Called when the item is dropped to a new location: @@ -144,6 +144,14 @@ beforeDrag?: (params: { elements: Element[]; index: number }) => void; Called when a valid drag is initiated. It provides a direct access to all list DOM elements and the index of dragged item. This can be useful when you need to do some upfront measurements like when building a [table with variable column widths](https://react-movable.netlify.app/?story=list--table-auto-cell-widths). +### afterDrag + +```ts +afterDrag?: (params: { elements: Element[]; oldIndex: number; newIndex: number }) => void; +``` + +Called when a drag is completed. It provides a direct access to all list DOM elements, the old as well as the new index of the dragged item. This can be useful when you need to perform some cleanup, e.g. in conjunction with `beforeDrag`. Please note this is different to `onChange`, which will _only_ fire when the drag results in a changed order. + ### removableByMove ```ts diff --git a/examples/TableAuto.tsx b/examples/TableAuto.tsx index f888394..344584e 100644 --- a/examples/TableAuto.tsx +++ b/examples/TableAuto.tsx @@ -59,6 +59,9 @@ const TableAuto: React.FC = () => { ); setWidths(widths); }} + afterDrag={() => { + setWidths([]); + }} values={items} onChange={({ oldIndex, newIndex }) => setItems(arrayMove(items, oldIndex, newIndex)) diff --git a/src/List.tsx b/src/List.tsx index e509a30..8d37320 100644 --- a/src/List.tsx +++ b/src/List.tsx @@ -477,16 +477,26 @@ class List extends React.Component> { finishDrop = () => { const removeItem = this.props.removableByMove && this.isDraggedItemOutOfBounds(); - if ( - removeItem || - (this.afterIndex > -2 && this.state.itemDragged !== this.afterIndex) - ) { + const oldIndex = this.state.itemDragged; + const hasChanged = this.afterIndex > -2 && oldIndex !== this.afterIndex; + const newIndex = hasChanged + ? removeItem + ? -1 + : Math.max(this.afterIndex, 0) + : oldIndex; + if (removeItem || hasChanged) { this.props.onChange({ - oldIndex: this.state.itemDragged, - newIndex: removeItem ? -1 : Math.max(this.afterIndex, 0), + oldIndex, + newIndex, targetRect: this.ghostRef.current!.getBoundingClientRect(), }); } + this.props.afterDrag && + this.props.afterDrag({ + elements: this.getChildren(), + oldIndex, + newIndex, + }); this.getChildren().forEach((item) => { setItemTransition(item, 0); transformItem(item, null); diff --git a/src/index.ts b/src/index.ts index f9db2b7..940cbb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import type { RenderItemParams, RenderListParams, BeforeDragParams, + AfterDragParams, OnChangeMeta, IProps, TEvent, @@ -16,6 +17,7 @@ export type { RenderItemParams, RenderListParams, BeforeDragParams, + AfterDragParams, OnChangeMeta, IProps, TEvent, diff --git a/src/types.ts b/src/types.ts index e3155f0..12caca6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,15 +39,22 @@ export interface BeforeDragParams { index: number; } +export interface AfterDragParams { + elements: Element[]; + oldIndex: number; + newIndex: number; +} + export interface OnChangeMeta { oldIndex: number; newIndex: number; - targetRect: ClientRect; + targetRect: DOMRect; } export interface IProps { disabled?: boolean; beforeDrag?: (params: BeforeDragParams) => void; + afterDrag?: (params: AfterDragParams) => void; renderItem: (params: RenderItemParams) => React.ReactNode; renderList: (props: RenderListParams) => React.ReactNode; values: Value[];