SortableList.jsx
2 years ago
SortableListItem.jsx
2 years ago
editor.scss
2 years ago
index.js
2 years ago
SortableList.jsx
108 lines
| 1 | import { useState, forwardRef } from '@wordpress/element'; |
| 2 | import { __ } from '@wordpress/i18n'; |
| 3 | import { |
| 4 | DndContext, |
| 5 | closestCenter, |
| 6 | KeyboardSensor, |
| 7 | PointerSensor, |
| 8 | useSensor, |
| 9 | useSensors, |
| 10 | } from '@dnd-kit/core'; |
| 11 | import { |
| 12 | arrayMove, |
| 13 | SortableContext, |
| 14 | sortableKeyboardCoordinates, |
| 15 | verticalListSortingStrategy, |
| 16 | } from '@dnd-kit/sortable'; |
| 17 | import { |
| 18 | restrictToVerticalAxis, |
| 19 | restrictToParentElement, |
| 20 | } from '@dnd-kit/modifiers'; |
| 21 | import { SortableListItem } from './SortableListItem.jsx'; |
| 22 | import classnames from 'classnames'; |
| 23 | |
| 24 | import './editor.scss'; |
| 25 | |
| 26 | export const SortableList = forwardRef( function SortableList( { |
| 27 | itemComponent, |
| 28 | onDragStart, |
| 29 | onDragEnd, |
| 30 | items, |
| 31 | setItems, |
| 32 | dragHandle = true, |
| 33 | dragHandleLabel = __( 'Reorder Item', 'generateblocks' ), |
| 34 | className = '', |
| 35 | }, ref ) { |
| 36 | const [ isDragging, setIsDragging ] = useState( false ); |
| 37 | const [ activeItem, setActiveItem ] = useState( null ); |
| 38 | const sensors = useSensors( |
| 39 | useSensor( PointerSensor ), |
| 40 | useSensor( KeyboardSensor, { |
| 41 | coordinateGetter: sortableKeyboardCoordinates, |
| 42 | } ) |
| 43 | ); |
| 44 | |
| 45 | const ItemComponent = itemComponent; |
| 46 | |
| 47 | function reorderItems( event ) { |
| 48 | const { active, over } = event; |
| 49 | const overDisabled = over.data.current?.disabled ?? false; |
| 50 | |
| 51 | if ( active.id !== over.id && ! overDisabled ) { |
| 52 | const oldIndex = items.findIndex( ( item ) => item.id === active.id ); |
| 53 | const newIndex = items.findIndex( ( item ) => item.id === over.id ); |
| 54 | |
| 55 | setItems( arrayMove( items, oldIndex, newIndex ) ); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | return ( |
| 60 | <DndContext |
| 61 | modifiers={ [ restrictToVerticalAxis, restrictToParentElement ] } |
| 62 | sensors={ sensors } |
| 63 | collisionDetection={ closestCenter } |
| 64 | onDragStart={ ( e ) => { |
| 65 | const { active } = e; |
| 66 | setIsDragging( true ); |
| 67 | setActiveItem( active ); |
| 68 | |
| 69 | if ( onDragStart ) { |
| 70 | onDragStart( e ); |
| 71 | } |
| 72 | } } |
| 73 | onDragEnd={ ( e ) => { |
| 74 | setIsDragging( false ); |
| 75 | reorderItems( e ); |
| 76 | setActiveItem( null ); |
| 77 | |
| 78 | if ( onDragEnd ) { |
| 79 | onDragEnd( e, activeItem ); |
| 80 | } |
| 81 | } } |
| 82 | > |
| 83 | <ul |
| 84 | className={ classnames( 'gb-sortable-list', className, isDragging && 'is-dragging' ) } |
| 85 | ref={ ref } |
| 86 | > |
| 87 | <SortableContext |
| 88 | items={ items } |
| 89 | strategy={ verticalListSortingStrategy } |
| 90 | > |
| 91 | { items.map( ( item ) => ( |
| 92 | <SortableListItem |
| 93 | key={ item.id } |
| 94 | id={ item.id } |
| 95 | dragHandle={ dragHandle } |
| 96 | dragHandleLabel={ dragHandleLabel } |
| 97 | className="gb-sortable-list__item" |
| 98 | disabled={ item.disabled ?? false } |
| 99 | > |
| 100 | <ItemComponent item={ item } /> |
| 101 | </SortableListItem> |
| 102 | ) ) } |
| 103 | </SortableContext> |
| 104 | </ul> |
| 105 | </DndContext> |
| 106 | ); |
| 107 | } ); |
| 108 |