Skip to content

Commit 24cf9d6

Browse files
dhayabsarahdayan
andauthored
fix: stop touchstart event propagation if coming from cancel button in detached mode (#924)
Co-authored-by: Sarah Dayan <[email protected]>
1 parent 9e8f9e6 commit 24cf9d6

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

packages/autocomplete-js/src/__tests__/detached.test.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,30 @@ describe('detached', () => {
111111
'.aa-DetachedCancelButton'
112112
);
113113

114-
const bodyClickListener = jest.fn();
115-
document.querySelector('body').addEventListener('click', bodyClickListener);
114+
// Prevent `onTouchStart` event from closing detached overlay
115+
const windowTouchStartListener = jest.fn();
116+
window.addEventListener('touchstart', windowTouchStartListener);
117+
118+
fireEvent(
119+
cancelButton,
120+
new TouchEvent('touchstart', {
121+
bubbles: true,
122+
cancelable: true,
123+
composed: true,
124+
})
125+
);
116126

117-
// Close detached overlay
118-
cancelButton.click();
127+
expect(windowTouchStartListener).toHaveBeenCalledTimes(0);
119128

120-
expect(bodyClickListener).toHaveBeenCalledTimes(0);
129+
window.removeEventListener('touchstart', windowTouchStartListener);
130+
131+
await waitFor(() => {
132+
expect(document.querySelector('.aa-DetachedOverlay')).toBeInTheDocument();
133+
expect(document.body).toHaveClass('aa-Detached');
134+
});
121135

122-
document
123-
.querySelector('body')
124-
.removeEventListener('click', bodyClickListener);
136+
// Close detached overlay
137+
cancelButton.click();
125138

126139
// The detached overlay should close
127140
await waitFor(() => {

packages/autocomplete-js/src/createAutocompleteDom.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,12 @@ export function createAutocompleteDom<TItem extends BaseItem>({
169169
type: 'button',
170170
class: classNames.detachedCancelButton,
171171
textContent: translations.detachedCancelButtonText,
172-
onClick(event: MouseEvent) {
172+
// Prevent `onTouchStart` from closing the panel
173+
// since it should be initiated by `onClick` only
174+
onTouchStart(event: TouchEvent) {
173175
event.stopPropagation();
176+
},
177+
onClick() {
174178
autocomplete.setIsOpen(false);
175179
setIsModalOpen(false);
176180
},

packages/autocomplete-js/src/utils/setProperties.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
/* eslint-disable */
22

3+
/**
4+
* Touch-specific event aliases
5+
*
6+
* See https://w3c.github.io/touch-events/#extensions-to-the-globaleventhandlers-mixin
7+
*/
8+
const TOUCH_EVENTS_ALIASES = [
9+
'ontouchstart',
10+
'ontouchend',
11+
'ontouchmove',
12+
'ontouchcancel',
13+
];
14+
315
/*
416
* Taken from Preact
517
*
@@ -50,7 +62,8 @@ export function setProperty(dom: HTMLElement, name: string, value: any) {
5062
else if (name[0] === 'o' && name[1] === 'n') {
5163
useCapture = name !== (name = name.replace(/Capture$/, ''));
5264
nameLower = name.toLowerCase();
53-
if (nameLower in dom) name = nameLower;
65+
if (nameLower in dom || TOUCH_EVENTS_ALIASES.includes(nameLower))
66+
name = nameLower;
5467
name = name.slice(2);
5568

5669
if (!(dom as any)._listeners) (dom as any)._listeners = {};

0 commit comments

Comments
 (0)