Skip to content

Commit e798ea0

Browse files
committed
fix(ui-a11y-utils): make Modal stay open when button is clicked in certain configurations
INSTUI-4483
1 parent 142c508 commit e798ea0

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

cypress/component/Modal.cy.tsx

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
* SOFTWARE.
2323
*/
2424
import React, { useState } from 'react'
25-
import { Modal, View } from '../../packages/ui'
25+
import { Modal, View, Button } from '@instructure/ui'
26+
import 'cypress-real-events'
2627

2728
import '../support/component'
2829

@@ -105,4 +106,69 @@ describe('<Modal/>', () => {
105106
cy.get('body').click(0, 0)
106107
cy.wrap(handleDismissSpy).should('have.been.calledOnceWith', 1)
107108
})
109+
110+
it('should not close when button is clicked to rerender content', () => {
111+
const TestModal = () => {
112+
const [isOpen, setIsOpen] = useState(false)
113+
const [state, setState] = useState({
114+
content:
115+
'This content should change by clicking on the Change content button',
116+
isButtonVisible: true
117+
})
118+
119+
return (
120+
<div>
121+
<Button onClick={() => setIsOpen(true)}>Open the Modal</Button>
122+
123+
{isOpen && (
124+
<Modal
125+
label="label"
126+
open
127+
onDismiss={() => setIsOpen(false)}
128+
shouldCloseOnDocumentClick
129+
>
130+
<Modal.Body>
131+
<div data-testid="modal-content">{state.content}</div>
132+
{state.isButtonVisible && (
133+
<Button
134+
onClick={() =>
135+
setState({
136+
content: 'The content has changed!',
137+
isButtonVisible: false
138+
})
139+
}
140+
data-testid="change-content-button"
141+
>
142+
Change content
143+
</Button>
144+
)}
145+
<Button
146+
data-testid="close-button"
147+
onClick={() => setIsOpen(false)}
148+
>
149+
Close
150+
</Button>
151+
</Modal.Body>
152+
</Modal>
153+
)}
154+
</div>
155+
)
156+
}
157+
158+
cy.mount(<TestModal />)
159+
160+
cy.contains('Open the Modal').realClick()
161+
162+
cy.get('[data-testid="modal-content"]').should('be.visible')
163+
164+
cy.get('[data-testid="change-content-button"]')
165+
.realClick()
166+
.then(() => cy.get('[data-testid="modal-content"]').should('be.visible'))
167+
168+
cy.get('[data-testid="close-button"]').should('be.visible')
169+
170+
cy.get('[data-testid="close-button"]').realClick()
171+
172+
cy.get('[data-testid="modal-content"]').should('not.exist')
173+
})
108174
})

packages/ui-a11y-utils/src/FocusRegion.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class FocusRegion {
4545
private readonly _id: string
4646
private _listeners: ReturnType<typeof addEventListener>[] = []
4747
private _active = false
48-
private _documentMouseDownTarget: Node | null = null
48+
private _documentClickTarget: Node | null = null
49+
private _contextContainsTarget = false
4950

5051
constructor(element: Element | Node | null, options: FocusRegionOptions) {
5152
this._options = options || {
@@ -83,17 +84,19 @@ class FocusRegion {
8384
}
8485

8586
captureDocumentMousedown = (event: React.MouseEvent) => {
86-
// FocusRegion can be activated after mousedown but before click so this is not guaranteed to fire.
87-
this._documentMouseDownTarget = event.target as Node
87+
this._documentClickTarget = event.target as Node
88+
this._contextContainsTarget = contains(
89+
this._contextElement,
90+
this._documentClickTarget
91+
)
8892
}
8993

9094
handleDocumentClick = (event: React.PointerEvent) => {
9195
if (
9296
this._options.shouldCloseOnDocumentClick &&
9397
event.button === 0 &&
9498
event.detail > 0 && // if event.detail is 0 then this is a keyboard and not a mouse press
95-
this._documentMouseDownTarget !== null &&
96-
!contains(this._contextElement, this._documentMouseDownTarget)
99+
!this._contextContainsTarget
97100
) {
98101
this.handleDismiss(event, true)
99102
}

0 commit comments

Comments
 (0)