@@ -1520,4 +1520,86 @@ for (const usingRemoveActiveDescendant of [false, true]) {
15201520 } )
15211521 } )
15221522 } )
1523+
1524+ describe ( 'Event propagation' , ( ) => {
1525+ function EventSelectPanel ( ) {
1526+ const [ selected , setSelected ] = React . useState < SelectPanelProps [ 'items' ] > ( [ ] )
1527+ const [ filter , setFilter ] = React . useState ( '' )
1528+ const [ open , setOpen ] = React . useState ( false )
1529+
1530+ const onSelectedChange = ( selected : SelectPanelProps [ 'items' ] ) => {
1531+ setSelected ( selected )
1532+ }
1533+
1534+ return (
1535+ < div
1536+ onKeyDown = { ( e : React . KeyboardEvent < HTMLDivElement > ) => {
1537+ const isAlphabetKey = e . key . length === 1 && / [ a - z \d ] / i. test ( e . key )
1538+ const container = e . currentTarget
1539+
1540+ if ( ! isAlphabetKey ) return
1541+ container . setAttribute ( 'data-keydown-called' , 'true' )
1542+ } }
1543+ data-keydown-called = "false"
1544+ >
1545+ < button type = "button" onClick = { ( ) => setOpen ( ! open ) } >
1546+ Toggle SelectPanel
1547+ </ button >
1548+ < SelectPanel
1549+ title = "test title"
1550+ subtitle = "test subtitle"
1551+ items = { items }
1552+ placeholder = "Select items"
1553+ placeholderText = "Filter items"
1554+ selected = { selected }
1555+ onSelectedChange = { onSelectedChange }
1556+ filterValue = { filter }
1557+ onFilterChange = { value => {
1558+ setFilter ( value )
1559+ } }
1560+ open = { open }
1561+ onOpenChange = { isOpen => {
1562+ setOpen ( isOpen )
1563+ } }
1564+ _PrivateFocusManagement = "roving-tabindex"
1565+ />
1566+ </ div >
1567+ )
1568+ }
1569+
1570+ it ( 'should prevent event propagation when using keyboard while focusing on an item' , async ( ) => {
1571+ const user = userEvent . setup ( )
1572+
1573+ render ( < EventSelectPanel /> )
1574+
1575+ const toggleButton = screen . getByRole ( 'button' , { name : 'Toggle SelectPanel' } )
1576+ const container = toggleButton . parentElement as HTMLDivElement
1577+
1578+ await user . click ( toggleButton )
1579+
1580+ expect ( screen . getByText ( 'Select items' ) ) . toBeInTheDocument ( )
1581+
1582+ const listbox = screen . getByRole ( 'listbox' )
1583+ expect ( listbox ) . toBeInTheDocument ( )
1584+ expect ( listbox ) . toHaveAttribute ( 'aria-multiselectable' , 'true' )
1585+
1586+ const options = screen . getAllByRole ( 'option' )
1587+ expect ( options ) . toHaveLength ( 3 )
1588+
1589+ const firstOption = options [ 0 ]
1590+ expect ( firstOption ) . toHaveTextContent ( 'item one' )
1591+
1592+ await user . keyboard ( '{ArrowDown}' )
1593+
1594+ expect ( firstOption ) . toHaveFocus ( )
1595+
1596+ await user . keyboard ( '{ArrowDown}' )
1597+
1598+ // Trigger alphabet key that should not propagate
1599+ await user . keyboard ( 'A' )
1600+
1601+ expect ( options [ 1 ] ) . toHaveFocus ( )
1602+ expect ( container . getAttribute ( 'data-keydown-called' ) ) . toBe ( 'false' )
1603+ } )
1604+ } )
15231605}
0 commit comments