-
Notifications
You must be signed in to change notification settings - Fork 236
fix: improve touch interaction handling for submenus #5867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: e8cf182 The changes in this PR will be included in the next version bump. This PR includes changesets to release 78 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📚 Branch Preview🔍 Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
934adf0 to
a8163fd
Compare
|
I am unable to open any submenu. Can you please check your logic once again. submenu.mov |
caseyisonit
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ran through the manual tests and this proposed fix is not working. submenus do not open at all. This needs more work on the logic to be considered.
…lose and reopen - Add _touchListenerActive flag to prevent multiple pointerup listeners from being registered - Reset flag in handleTouchSubmenuToggle after action completes - Prevents rapid close/reopen behavior when tapping on menu items with open submenus
7147e73 to
85cb5a8
Compare
- Add click event dispatch after touch tap to cover handleSubmenuClick touch prevention - Add touch pointerleave test to cover early return for touch devices - Add test for pointerdown on open submenu followed by focus to cover handleSubmenuFocus These targeted test enhancements improve coverage without adding entirely new test cases.
|
@shipg22 On my initial first pass the solution is not working for nested submenus.Please check and verify so that I can look into your logic more deeply. Attached video for reference. |
Rajdeepc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approach is good, but the implementation needs some hardening. Let me know if you would like to discuss on any of these!
| if ( | ||
| event.pointerType === 'touch' && | ||
| this.hasSubmenu && | ||
| event.target === this && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
event.target === this is brittle in shadow DOM. When the element has a shadow DOM or children inside the component) pointer events often have event.target equal to an inner element, not the host element (this). The current checks (event.target === this) will often fail and skip the intended logic.
You can use event.composedPath() or event.currentTarget instead
| event.target === this && | ||
| !this._touchListenerActive | ||
| ) { | ||
| event.preventDefault(); // Prevent click suppression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preventDefault on pointerdown may suppress subsequent click or change expected browser behavior. This comment is also bit misleading. Can you please explain why this is required here?
If the intent is to prevent a synthetic click from triggering the overlay twice, then you should ensure cleanup via pointerup/pointercancel and ignore click in handleSubmenuClick based on pointerType
|
|
||
| protected handlePointerenter(): void { | ||
| protected handlePointerenter(event: PointerEvent): void { | ||
| this._lastPointerType = event.pointerType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_lastPointerType can become stale across interactions when you logic grows large and it should be scoped to the active pointer. You can use pointerId instead.
| event.stopPropagation(); // Prevent bubbling to parent menu items | ||
| this._touchListenerActive = true; | ||
| this.addEventListener('pointerup', this.handleTouchSubmenuToggle, { | ||
| once: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pointerup listener attached to this with once:true can never fire or not fire in some touch scenarios like when finger moves off the element which will result in _touchListenerActive stuck true.
You can use pointerup/pointercancel handlers on window/document or the host root to ensure cleanup, and clear them in the handler.
| } | ||
|
|
||
| protected handleSubmenuClick(event: Event): void { | ||
| const pointerEvent = event as PointerEvent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unsafe casting. You are using pointerEvent.pointerType but click handlers typically receive MouseEvent or generic Event. pointerType will be undefined
| // Toggle the submenu | ||
| if (this.open) { | ||
| this.open = false; | ||
| } else { | ||
| this.openOverlay(true); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are doing if (this.open) this.open = false; else this.openOverlay(true); Elsewhere you call this.openOverlay(true). Please ensure that closing/opening is consistently done via one API to avoid confusion and mismatched cleanup.
Description
Submenu interaction is fixed for touch devices.
Submenu should open on hover for desktop and on click for touch devices.
First click should open, and second click should close the submenu on touch devices.
Motivation and context
Related issue(s)
[CCEX-244009]
Screenshots (if appropriate)
Author's checklist
Reviewer's checklist
patch,minor, ormajorfeaturesManual review test cases
Storybook
In dev tool select any touch screen device, for eg; iPad mini
open menu
Touch submenu under menu
Touch any submenu item
it should open menu under submenu if available, otherwise would select that item
Touch any nested menu item, it should open submenu if available, otherwise would select that item
Subsequent touch should open and close submenus
Device review