Skip to content

Commit 7bfe787

Browse files
authored
Merge branch 'master' into skrastev/localization-package
2 parents ada136b + 9aad8af commit 7bfe787

File tree

1 file changed

+43
-34
lines changed

1 file changed

+43
-34
lines changed

src/components/common/controllers/root-click.ts

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@ interface RootClickControllerHost extends ReactiveControllerHost, HTMLElement {
3333
hide(): void;
3434
}
3535

36-
let rootClickListenerActive = false;
37-
let pointerDownInsideHost = false;
36+
let ROOT_CLICK_LISTENER_ACTIVE = false;
37+
38+
/** Shared abort handler for the singleton document listeners. */
39+
const SHARED_ABORT_HANDLER = createAbortHandle();
40+
41+
/** Tracks which hosts had a pointerdown event inside them. */
42+
const POINTER_DOWN_HOSTS = new Set<RootClickControllerHost>();
3843

3944
const HOST_CONFIGURATIONS = new WeakMap<
4045
RootClickControllerHost,
@@ -43,45 +48,42 @@ const HOST_CONFIGURATIONS = new WeakMap<
4348

4449
const ACTIVE_HOSTS = new Set<RootClickControllerHost>();
4550

51+
/** Returns the set of elements that should be considered as "inside" the host. */
52+
function getHostTargets(
53+
host: RootClickControllerHost,
54+
config?: RootClickControllerConfig
55+
): Set<Element> {
56+
return new Set(config?.target ? [host, config.target] : [host]);
57+
}
58+
4659
function handlePointerDown(event: PointerEvent): void {
47-
// Check if the pointerdown occurred inside any active host or its target
60+
POINTER_DOWN_HOSTS.clear();
61+
4862
for (const host of ACTIVE_HOSTS) {
4963
const config = HOST_CONFIGURATIONS.get(host);
50-
const targets: Set<Element> = new Set(
51-
config?.target ? [host, config.target] : [host]
52-
);
64+
const targets = getHostTargets(host, config);
5365

5466
if (findElementFromEventPath((node) => targets.has(node), event)) {
55-
pointerDownInsideHost = true;
56-
return;
67+
POINTER_DOWN_HOSTS.add(host);
5768
}
5869
}
59-
60-
pointerDownInsideHost = false;
6170
}
6271

6372
function handleRootClick(event: PointerEvent): void {
64-
// If the interaction started inside a host, don't trigger hide
65-
if (pointerDownInsideHost) {
66-
pointerDownInsideHost = false;
67-
return;
68-
}
69-
70-
for (const host of ACTIVE_HOSTS) {
71-
const config = HOST_CONFIGURATIONS.get(host);
72-
73-
if (host.keepOpenOnOutsideClick) {
73+
for (const host of [...ACTIVE_HOSTS]) {
74+
if (host.keepOpenOnOutsideClick || POINTER_DOWN_HOSTS.has(host)) {
7475
continue;
7576
}
7677

77-
const targets: Set<Element> = new Set(
78-
config?.target ? [host, config.target] : [host]
79-
);
78+
const config = HOST_CONFIGURATIONS.get(host);
79+
const targets = getHostTargets(host, config);
8080

8181
if (!findElementFromEventPath((node) => targets.has(node), event)) {
8282
config?.onHide ? config.onHide.call(host) : host.hide();
8383
}
8484
}
85+
86+
POINTER_DOWN_HOSTS.clear();
8587
}
8688

8789
/* blazorSuppress */
@@ -96,7 +98,6 @@ function handleRootClick(event: PointerEvent): void {
9698
*/
9799
class RootClickController implements ReactiveController {
98100
private readonly _host: RootClickControllerHost;
99-
private readonly _abortHandler = createAbortHandle();
100101
private _config?: RootClickControllerConfig;
101102

102103
constructor(
@@ -121,14 +122,20 @@ class RootClickController implements ReactiveController {
121122

122123
if (this._config) {
123124
HOST_CONFIGURATIONS.set(this._host, this._config);
125+
}
124126

125-
if (!rootClickListenerActive) {
126-
const options = { capture: true, signal: this._abortHandler.signal };
127-
128-
document.addEventListener('pointerdown', handlePointerDown, options);
129-
document.addEventListener('click', handleRootClick, options);
130-
rootClickListenerActive = true;
131-
}
127+
if (!ROOT_CLICK_LISTENER_ACTIVE) {
128+
const options: AddEventListenerOptions = {
129+
capture: true,
130+
signal: SHARED_ABORT_HANDLER.signal,
131+
};
132+
133+
document.addEventListener('pointerdown', handlePointerDown, {
134+
...options,
135+
passive: true,
136+
});
137+
document.addEventListener('click', handleRootClick, options);
138+
ROOT_CLICK_LISTENER_ACTIVE = true;
132139
}
133140
}
134141

@@ -138,10 +145,12 @@ class RootClickController implements ReactiveController {
138145
*/
139146
private _removeActiveHost(): void {
140147
ACTIVE_HOSTS.delete(this._host);
148+
HOST_CONFIGURATIONS.delete(this._host);
149+
POINTER_DOWN_HOSTS.delete(this._host);
141150

142-
if (isEmpty(ACTIVE_HOSTS) && rootClickListenerActive) {
143-
this._abortHandler.abort();
144-
rootClickListenerActive = false;
151+
if (isEmpty(ACTIVE_HOSTS) && ROOT_CLICK_LISTENER_ACTIVE) {
152+
SHARED_ABORT_HANDLER.abort();
153+
ROOT_CLICK_LISTENER_ACTIVE = false;
145154
}
146155
}
147156

0 commit comments

Comments
 (0)