@@ -1242,6 +1242,86 @@ describe('ListBox', () => {
12421242 keyPress ( 'Escape' ) ;
12431243 act ( ( ) => jest . runAllTimers ( ) ) ;
12441244 } ) ;
1245+
1246+ it ( 'should support onAction with drag and drop in virtualized list' , async ( ) => {
1247+ let items = [ ] ;
1248+ for ( let i = 0 ; i < 20 ; i ++ ) {
1249+ items . push ( { id : i , name : 'Item ' + i } ) ;
1250+ }
1251+
1252+ jest . restoreAllMocks ( ) ;
1253+ jest . spyOn ( window . HTMLElement . prototype , 'clientWidth' , 'get' ) . mockImplementation ( ( ) => 100 ) ;
1254+ jest . spyOn ( window . HTMLElement . prototype , 'clientHeight' , 'get' ) . mockImplementation ( ( ) => 100 ) ;
1255+
1256+ let onAction = jest . fn ( ) ;
1257+ let onReorder = jest . fn ( ) ;
1258+
1259+ function VirtualizedDraggableListBox ( ) {
1260+ let { dragAndDropHooks} = useDragAndDrop ( {
1261+ getItems : ( keys ) => [ ...keys ] . map ( ( key ) => ( { 'text/plain' : key } ) ) ,
1262+ onReorder,
1263+ renderDropIndicator : ( target ) => < DropIndicator target = { target } > Drop</ DropIndicator >
1264+ } ) ;
1265+
1266+ return (
1267+ < Virtualizer layout = { ListLayout } layoutOptions = { { rowHeight : 25 } } >
1268+ < ListBox
1269+ aria-label = "Test"
1270+ dragAndDropHooks = { dragAndDropHooks }
1271+ onAction = { onAction }
1272+ items = { items } >
1273+ { item => < ListBoxItem > { item . name } </ ListBoxItem > }
1274+ </ ListBox >
1275+ </ Virtualizer >
1276+ ) ;
1277+ }
1278+
1279+ let { getAllByRole} = render ( < VirtualizedDraggableListBox /> ) ;
1280+ let options = getAllByRole ( 'option' ) ;
1281+
1282+ // Focus first item
1283+ await user . tab ( ) ;
1284+ expect ( document . activeElement ) . toBe ( options [ 0 ] ) ;
1285+
1286+ // Pressing Enter should trigger onAction, and not start drag
1287+ keyPress ( 'Enter' ) ;
1288+ act ( ( ) => jest . runAllTimers ( ) ) ;
1289+ expect ( onAction ) . toHaveBeenCalledTimes ( 1 ) ;
1290+ expect ( onAction ) . toHaveBeenCalledWith ( 0 ) ;
1291+ expect ( onReorder ) . not . toHaveBeenCalled ( ) ;
1292+
1293+ // Should not be in drag mode
1294+ options = getAllByRole ( 'option' ) ;
1295+ expect ( options . filter ( opt => opt . classList . contains ( 'react-aria-DropIndicator' ) ) ) . toHaveLength ( 0 ) ;
1296+
1297+ // Now test that Alt+Enter starts drag mode
1298+ expect ( document . activeElement ) . toBe ( options [ 0 ] ) ;
1299+ fireEvent . keyDown ( document . activeElement , { key : 'Enter' , altKey : true } ) ;
1300+ fireEvent . keyUp ( document . activeElement , { key : 'Enter' , altKey : true } ) ;
1301+ act ( ( ) => jest . runAllTimers ( ) ) ;
1302+
1303+ // Verify we're in drag mode
1304+ options = getAllByRole ( 'option' ) ;
1305+ let dropIndicators = options . filter ( opt => opt . classList . contains ( 'react-aria-DropIndicator' ) ) ;
1306+ expect ( dropIndicators . length ) . toBeGreaterThan ( 0 ) ;
1307+ expect ( document . activeElement ) . toHaveAttribute ( 'aria-label' ) ;
1308+ expect ( document . activeElement . getAttribute ( 'aria-label' ) ) . toContain ( 'Insert' ) ;
1309+
1310+ // onAction should not have been called again
1311+ expect ( onAction ) . toHaveBeenCalledTimes ( 1 ) ;
1312+
1313+ // Complete the drop
1314+ keyPress ( 'ArrowDown' ) ;
1315+ expect ( document . activeElement . getAttribute ( 'aria-label' ) ) . toContain ( 'Insert' ) ;
1316+ keyPress ( 'Enter' ) ;
1317+ act ( ( ) => jest . runAllTimers ( ) ) ;
1318+
1319+ expect ( onReorder ) . toHaveBeenCalledTimes ( 1 ) ;
1320+
1321+ // Verify we're no longer in drag mode
1322+ options = getAllByRole ( 'option' ) ;
1323+ expect ( options . filter ( opt => opt . classList . contains ( 'react-aria-DropIndicator' ) ) ) . toHaveLength ( 0 ) ;
1324+ } ) ;
12451325 } ) ;
12461326
12471327 describe ( 'inside modals' , ( ) => {
0 commit comments