@@ -14,7 +14,7 @@ import {action} from '@storybook/addon-actions';
14
14
import { Button , Calendar , CalendarCell , CalendarGrid , Cell , Checkbox , Column , ColumnResizer , ComboBox , DateField , DateInput , DatePicker , DateRangePicker , DateSegment , Dialog , DialogTrigger , DropZone , FileTrigger , Group , Header , Heading , Input , Item , Keyboard , Label , Link , ListBox , ListBoxProps , Menu , MenuTrigger , Modal , ModalOverlay , NumberField , OverlayArrow , Popover , Radio , RadioGroup , RangeCalendar , ResizableTableContainer , Row , SearchField , Section , Select , SelectValue , Separator , Slider , SliderOutput , SliderThumb , SliderTrack , Switch , Tab , Table , TableBody , TableHeader , TabList , TabPanel , Tabs , TabsProps , Tag , TagGroup , TagList , Text , TextField , TimeField , ToggleButton , Toolbar , Tooltip , TooltipTrigger , useDragAndDrop } from 'react-aria-components' ;
15
15
import { classNames } from '@react-spectrum/utils' ;
16
16
import clsx from 'clsx' ;
17
- import { FocusRing , mergeProps , useButton , useClipboard , useDrag } from 'react-aria' ;
17
+ import { FocusRing , isTextDropItem , mergeProps , useButton , useClipboard , useDrag } from 'react-aria' ;
18
18
import React , { useRef , useState } from 'react' ;
19
19
import { RouterProvider } from '@react-aria/utils' ;
20
20
import styles from '../example/index.css' ;
@@ -713,6 +713,82 @@ export const TabsRenderProps = () => {
713
713
) ;
714
714
} ;
715
715
716
+ const ReorderableTable = ( { initialItems} : { initialItems : { id : string , name : string } [ ] } ) => {
717
+ let list = useListData ( { initialItems} ) ;
718
+
719
+ const { dragAndDropHooks} = useDragAndDrop ( {
720
+ getItems : keys => {
721
+ return [ ...keys ] . map ( k => {
722
+ const item = list . getItem ( k ) ;
723
+ return {
724
+ 'text/plain' : item . id ,
725
+ item : JSON . stringify ( item )
726
+ } ;
727
+ } ) ;
728
+ } ,
729
+ getDropOperation : ( ) => 'move' ,
730
+ onReorder : e => {
731
+ if ( e . target . dropPosition === 'before' ) {
732
+ list . moveBefore ( e . target . key , e . keys ) ;
733
+ } else if ( e . target . dropPosition === 'after' ) {
734
+ list . moveAfter ( e . target . key , e . keys ) ;
735
+ }
736
+ } ,
737
+ onInsert : async e => {
738
+ const processedItems = await Promise . all (
739
+ e . items . filter ( isTextDropItem ) . map ( async item => JSON . parse ( await item . getText ( 'item' ) ) )
740
+ ) ;
741
+ if ( e . target . dropPosition === 'before' ) {
742
+ list . insertBefore ( e . target . key , ...processedItems ) ;
743
+ } else if ( e . target . dropPosition === 'after' ) {
744
+ list . insertAfter ( e . target . key , ...processedItems ) ;
745
+ }
746
+ } ,
747
+
748
+ onDragEnd : e => {
749
+ if ( e . dropOperation === 'move' && ! e . isInternal ) {
750
+ list . remove ( ...e . keys ) ;
751
+ }
752
+ } ,
753
+
754
+ onRootDrop : async e => {
755
+ const processedItems = await Promise . all (
756
+ e . items . filter ( isTextDropItem ) . map ( async item => JSON . parse ( await item . getText ( 'item' ) ) )
757
+ ) ;
758
+
759
+ list . append ( ...processedItems ) ;
760
+ }
761
+ } ) ;
762
+
763
+ return (
764
+ < Table aria-label = "Reorderable table" dragAndDropHooks = { dragAndDropHooks } >
765
+ < TableHeader >
766
+ < MyColumn isRowHeader defaultWidth = "50%" > Id</ MyColumn >
767
+ < MyColumn > Name</ MyColumn >
768
+ </ TableHeader >
769
+ < TableBody items = { list . items } renderEmptyState = { ( { isDropTarget} ) => < span style = { { color : isDropTarget ? 'red' : 'black' } } > Drop items here</ span > } >
770
+ { item => (
771
+ < Row >
772
+ < Cell > { item . id } </ Cell >
773
+ < Cell > { item . name } </ Cell >
774
+ </ Row >
775
+ ) }
776
+ </ TableBody >
777
+ </ Table >
778
+ ) ;
779
+ } ;
780
+
781
+ export const ReorderableTableExample = ( ) => (
782
+ < >
783
+ < ResizableTableContainer style = { { width : 300 , overflow : 'auto' } } >
784
+ < ReorderableTable initialItems = { [ { id : '1' , name : 'Bob' } ] } />
785
+ </ ResizableTableContainer >
786
+ < ResizableTableContainer style = { { width : 300 , overflow : 'auto' } } >
787
+ < ReorderableTable initialItems = { [ { id : '2' , name : 'Alex' } ] } />
788
+ </ ResizableTableContainer >
789
+ </ >
790
+ ) ;
791
+
716
792
export const TableExample = ( ) => {
717
793
let list = useListData ( {
718
794
initialItems : [
0 commit comments