Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Fixes
- Do not propagate keyboard events outside `Popup`'s content only when focus trap is used @sophieH29 ([#1028](https://github.com/stardust-ui/react/pull/1028))

### Features
- Add `inline` prop in the `Popup` for rendering the content next to the trigger element @mnajdova ([#1017](https://github.com/stardust-ui/react/pull/1017))

Expand Down
14 changes: 8 additions & 6 deletions packages/react/src/components/Popup/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -469,12 +469,7 @@ export default class Popup extends AutoControlledComponent<ReactProps<PopupProps
const popupWrapperAttributes = {
...(rtl && { dir: 'rtl' }),
...accessibility.attributes.popup,
onKeyDown: (e: React.KeyboardEvent) => {
// No need to propagate keydown events outside Popup
// allow only keyboard actions to execute
_.invoke(accessibility.keyHandlers.popup, 'onKeyDown', e)
e.stopPropagation()
},
...accessibility.keyHandlers.popup,
className: popupPositionClasses,
style: popupPlacementStyles,
...this.getContentProps(),
Expand All @@ -483,6 +478,13 @@ export default class Popup extends AutoControlledComponent<ReactProps<PopupProps
const focusTrapProps = {
...(typeof accessibility.focusTrap === 'boolean' ? {} : accessibility.focusTrap),
...popupWrapperAttributes,
onKeyDown: (e: React.KeyboardEvent) => {
// No need to propagate keydown events outside Popup
// when focus trap behavior is used
// allow only keyboard actions to execute
_.invoke(accessibility.keyHandlers.popup, 'onKeyDown', e)
e.stopPropagation()
},
} as FocusTrapZoneProps

const autoFocusProps = {
Expand Down
43 changes: 37 additions & 6 deletions packages/react/test/specs/components/Popup/Popup-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
Alignment,
} from 'src/components/Popup/positioningHelper'
import Popup, { PopupEvents } from 'src/components/Popup/Popup'
import { Accessibility } from 'src/lib/accessibility/types'
import { popupFocusTrapBehavior, popupBehavior, dialogBehavior } from 'src/lib/accessibility/index'

import { domEvent, mountWithProvider } from '../../../utils'
import * as keyboardKey from 'keyboard-key'
import { ReactWrapper } from 'enzyme'
Expand Down Expand Up @@ -68,12 +71,6 @@ describe('Popup', () => {

expect(getPopupContent(popup).exists()).toBe(true)

// when popup open, check that stopPropagation is called when keyboard events are invoked
const stopPropagation = jest.fn()
const popupContentElement = getPopupContent(popup)
popupContentElement.simulate('keyDown', { stopPropagation })
expect(stopPropagation).toHaveBeenCalledTimes(1)

// check popup closes on Esc
popupTriggerElement.simulate('keydown', { keyCode: keyboardKeyToClose })
expect(getPopupContent(popup).exists()).toBe(false)
Expand Down Expand Up @@ -266,4 +263,38 @@ describe('Popup', () => {
expect(contentElement.classList.contains(Popup.Content.className)).toEqual(true)
})
})

describe('keyboard event propagation', () => {
const expectPopupToHandleStopPropagation = (
behavior: Accessibility,
shouldStopPropagation: boolean,
) => {
const popup = mountWithProvider(
<Popup
trigger={<span id={triggerId}> text to trigger popup </span>}
content={<span id={contentId} />}
accessibility={behavior}
/>,
)

// open popup
const popupTriggerElement = popup.find(`#${triggerId}`)
popupTriggerElement.simulate('keydown', { keyCode: keyboardKey.Enter })

// when popup open, check that stopPropagation is called when keyboard events are invoked
const stopPropagation = jest.fn()
const popupContentElement = getPopupContent(popup)
popupContentElement.simulate('keyDown', { stopPropagation })
expect(stopPropagation).toHaveBeenCalledTimes(shouldStopPropagation ? 1 : 0)
}
test('stops when focus trap behavior is used', () => {
expectPopupToHandleStopPropagation(popupFocusTrapBehavior, true)
})
test('stops when dialog behavior is used', () => {
expectPopupToHandleStopPropagation(dialogBehavior, true)
})
test('does not stop when default behavior is used', () => {
expectPopupToHandleStopPropagation(popupBehavior, false)
})
})
})