Skip to content

Commit 51a8fbb

Browse files
authored
fix(navigation-menu): prevent accidental menu closing when clicking immediately after hover (#337)
1 parent 6285387 commit 51a8fbb

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

packages/primitives/navigation-menu/src/navigation-menu.directive.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export class RdxNavigationMenuDirective implements OnDestroy {
5656
private openTimerRef = 0;
5757
private closeTimerRef = 0;
5858
private skipDelayTimerRef = 0;
59+
private recentlyActivatedTimerRef = 0;
60+
private readonly recentlyActivatedItem = signal<string | null>(null);
5961
readonly #isOpenDelayed = signal(true);
6062

6163
// pointer tracking
@@ -67,6 +69,7 @@ export class RdxNavigationMenuDirective implements OnDestroy {
6769

6870
@Input() orientation: 'horizontal' | 'vertical' = 'horizontal';
6971
@Input() dir: 'ltr' | 'rtl' = 'ltr';
72+
@Input({ transform: numberAttribute }) clickIgnoreDuration = 250;
7073
@Input({ transform: numberAttribute }) delayDuration = 200;
7174
@Input({ transform: numberAttribute }) skipDelayDuration = 300;
7275
@Input({ transform: booleanAttribute }) loop = false;
@@ -148,6 +151,7 @@ export class RdxNavigationMenuDirective implements OnDestroy {
148151
this.window.clearTimeout(this.openTimerRef);
149152
this.window.clearTimeout(this.closeTimerRef);
150153
this.window.clearTimeout(this.skipDelayTimerRef);
154+
this.window.clearTimeout(this.recentlyActivatedTimerRef);
151155

152156
// clean up document event listener
153157
if (this.documentMouseLeaveHandler) {
@@ -198,6 +202,13 @@ export class RdxNavigationMenuDirective implements OnDestroy {
198202

199203
onItemSelect(itemValue: string) {
200204
const wasOpen = this.#value() === itemValue;
205+
206+
// if this item just opened and the click would close it,
207+
// ignore the click during the brief protection window
208+
if (this.recentlyActivatedItem() === itemValue && wasOpen) {
209+
return;
210+
}
211+
201212
const newValue = wasOpen ? '' : itemValue;
202213

203214
// if user is closing an open menu, mark as user-dismissed
@@ -229,8 +240,20 @@ export class RdxNavigationMenuDirective implements OnDestroy {
229240
}
230241

231242
private setValue(value: string) {
232-
// Store previous value before changing
233-
this.#previousValue.set(this.#value());
243+
const previousValue = this.#value();
244+
245+
if (value && value !== previousValue) {
246+
this.window.clearTimeout(this.recentlyActivatedTimerRef);
247+
248+
this.recentlyActivatedItem.set(value);
249+
250+
this.recentlyActivatedTimerRef = this.window.setTimeout(() => {
251+
this.recentlyActivatedItem.set(null);
252+
}, this.clickIgnoreDuration);
253+
}
254+
255+
// store previous value before changing
256+
this.#previousValue.set(previousValue);
234257
this.#value.set(value);
235258
}
236259

0 commit comments

Comments
 (0)