Repository navigation
fix(Item): the row's onClick ignores clicks from portals and role-based controls #9393
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?
Changes from all commits
a6ae3b8
1a806d3
859bc67
83ffa3a
b19b030
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| '@astryxdesign/core': patch | ||
| --- | ||
|
|
||
| [fix] A clickable Item or ListItem (one with `onClick` and no `role`) no longer runs it for a click that belongs to something else: a click inside content the caller portals out of the row with its own `createPortal`, or on a role-based control (`role="tab"`, `"switch"`, `"menuitem"` and the rest of the shared interactive list) nested in the row. (#8977) | ||
| @HelloOjasMutreja | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,6 +61,7 @@ import {computeTargetAndRel} from '../Link/computeTargetAndRel'; | |
| import {useLinkComponent} from '../Link/useLinkComponent'; | ||
| import { | ||
| cancelNestedTouchPress, | ||
| hasInteractiveAncestor, | ||
| PRESSABLE_CONTAINER_ATTRIBUTE, | ||
| useClickableContainerProxy, | ||
| } from '../hooks/useClickableContainer'; | ||
|
|
@@ -825,7 +826,16 @@ export function Item({ | |
| return; | ||
| } | ||
| const target = e.target as HTMLElement; | ||
| if (target.closest('button, a, input, select, textarea')) { | ||
| if ( | ||
| // React bubbles a click through a portal the caller renders from the | ||
| // row (its own `createPortal`), but its target is not in the row. | ||
| !e.currentTarget.contains(target) || | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Main now sends a List link row's surface click through this guard, so this line also stops content a |
||
| // A native control owns the click, as it always has (this also keeps a | ||
| // read-only input and a row inside a link or button inert). | ||
|
Comment on lines
+833
to
+834
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non-blocking: "as it always has" narrates history. Suggest keeping only the reason: "This check also looks above the row. It keeps a row inside a link or button inert, and a read-only input, which the shared walk skips." |
||
| target.closest('button, a, input, select, textarea') || | ||
| // So does a nested role-based control (role="tab", role="switch"). | ||
| hasInteractiveAncestor(target, e.currentTarget) | ||
| ) { | ||
| return; | ||
| } | ||
| if (isLinkRow) { | ||
|
|
||
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.
"and the rest of the shared interactive list" also covers
role="slider", but a pointer click on an AstryxSliderthumb in a clickable row still runs the row'sonClick: the Slider captures the pointer on its track, so the click lands on the track, outsiderole="slider". Suggest naming only what the tests prove: "…or on a nested element withrole="tab","switch","menuitem","checkbox"or"option"that receives the click."