-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Fix automation picker overflow menu for keyboard #21048
Fix automation picker overflow menu for keyboard #21048
Conversation
This comment was marked as off-topic.
This comment was marked as off-topic.
@@ -898,6 +906,12 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |||
`; | |||
} | |||
|
|||
private _handleMenuClose(ev) { | |||
if (ev.detail.reason.key === "Escape") return; | |||
const action = ev.currentTarget.action.bind(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.
Instead of using bind
, can we make the action functions arrow functions?
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.
I wonder if we should use a switch/case with a string action to call the right function instead of binding the function on the element.
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.
Instead of using target
or currentTarget
, use initiator
defined in the custom event detail. Then I wonder if the key/reason check is even necessary as hopefully that would be null
or undefined
unless the user actually took the action with space or enter?
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 initiator is still ha-menu-item
when canceling the menu with Escape key.
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.
I think this proposed change is way too much of a hack. It also presumes that escape is the only way to close the menu, which may not be the case at all, and then lead to activation the user didn't take.
MDMenuItem
extends MDListItem
, and so my guess here would be that the simple fix should be to use the @request-activation
event instead of @click
. I'm dealing with some data loss of my docker volumes so I cannot test that ATM.
The same problem exists when listening to click
instead of request-selected
on mwc-list-item
, so this is likely just a continuation of that with Material 3. I fixed many of those but many new ones using click
have popped up or regressed. For the record, that's why I've taken a hiatus from a11y recently - I'm working on something big to hopefully prevent such regressions in the future.
I might be missing something, but listening for |
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.
If request-activation
doesn't work, then I guess we're stuck with this approach until material-components/material-web#5577 gets resolved. To make it less fluffy on each instance, my suggestions are to move the crux of the handling to the element classes, and just require the instances to set the action to take.
@@ -898,6 +906,12 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |||
`; | |||
} | |||
|
|||
private _handleMenuClose(ev) { | |||
if (ev.detail.reason.key === "Escape") return; | |||
const action = ev.currentTarget.action.bind(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.
Instead of using target
or currentTarget
, use initiator
defined in the custom event detail. Then I wonder if the key/reason check is even necessary as hopefully that would be null
or undefined
unless the user actually took the action with space or enter?
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.
Other than the few suggestions below, LGTM. If you can swing it quick, I'll approve so we can fix this for 2024.7.
src/components/ha-menu-item.ts
Outdated
|
||
@customElement("ha-menu-item") | ||
export class HaMenuItem extends MdMenuItem { | ||
@property() closeAction?: (ev: CloseMenuEvent) => void; |
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.
A few suggestions to improve the API:
- Turn off the attribute. I don't know why lit-analyzer doesn't flag that function props shouldn't be attributes.
- Make the parameter the triggering item instead of the event, and make it optional as many handlers won't need it.
- To make the purpose much clearer where used in instances, maybe rename to
clickAction
or justaction
. @bramkragten any strong opinion here?
@property() closeAction?: (ev: CloseMenuEvent) => void; | |
@property({ attribute: false }) clickAction?: (item?: HTMLElement) => void; |
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.
What should be passed as the item
here, the ev.detail.initiator
?
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.
Yes
@@ -1051,28 +1051,28 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |||
this._applyFilters(); | |||
} | |||
|
|||
private _showInfo(ev) { | |||
const automation = ev.currentTarget.parentElement.anchorElement.automation; | |||
private _showInfo = (ev) => { |
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.
...then type the parameter as HaMenuItem
(trying to cut down on the way too many instances of implicit any
types we have).
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.
I will say that typing this is getting kind of ugly. I have to cast the parent element, then cast the anchorElement back to any
as the automation
property does not actually exist on any type, it's just a custom added thing here.
const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!.automation;
Is this going to be acceptable or need to clean it up somehow?
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.
I think it's fine for now. The best goal would be to turn on noImplicitAny
in tsconfig. Casting as any is never great, but that's a different rule for another day.
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.
Actionable comments posted: 6
Outside diff range comments (4)
src/panels/config/automation/ha-automation-picker.ts (4)
Line range hint
1078-1100
: Avoid non-null assertions andany
type.Consider using optional chaining and proper type annotations for better type safety.
- const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!.automation; + const automation = (item.parentElement as HaMenu)?.anchorElement?.automation as AutomationEntity;Tools
Biome
[error] 1056-1056: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1056-1056: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1056-1056: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 1062-1062: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1062-1062: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1062-1062: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 1072-1072: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1072-1072: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1072-1072: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
[error] 1079-1079: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1079-1079: Forbidden non-null assertion.
Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator
(lint/style/noNonNullAssertion)
[error] 1079-1079: Unexpected any. Specify a different type.
any disables many type checking rules. Its use should be avoided.
(lint/suspicious/noExplicitAny)
Line range hint
1102-1117
: Avoid non-null assertions andany
type.Consider using optional chaining and proper type annotations for better type safety.
- const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!.automation; + const automation = (item.parentElement as HaMenu)?.anchorElement?.automation as AutomationEntity;
Line range hint
1129-1146
: Avoid non-null assertions andany
type.Consider using optional chaining and proper type annotations for better type safety.
- const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!.automation; + const automation = (item.parentElement as HaMenu)?.anchorElement?.automation as AutomationEntity;
Line range hint
1166-1192
: Avoid non-null assertions andany
type.Consider using optional chaining and proper type annotations for better type safety.
- const automation = ((item.parentElement as HaMenu)!.anchorElement as any)!.automation; + const automation = (item.parentElement as HaMenu)?.anchorElement?.automation as AutomationEntity;
Proposed change
The current overflow menu in a lot of the new data tables cannot be used with the keyboard, as far as I can tell. Both enter or space close the menu without doing anything, neither of them trigger the click event. That seems like it is only triggered for
<a>
links, and only for Enter.Just reading https://material-web.dev/components/menu/ it seems like maybe
@close-event
could be a reasonable event to use instead of@click
so it can have keyboard support? The only drawback is it is also triggered by the escape key, which I've added a helper event to prevent actions on that.I'm not clear if this is intentional behavior of md-menu-item, could be slightly related to issue 5577 from github.com/material-components/material-web, but I'm not sure if a fix there would necessarily fix this either.
There are many menus that are affected by this, but I'll just start with this one to discuss a good pattern for a solution.
Type of change
Example configuration
Additional information
Checklist
If user exposed functionality or configuration variables are added/changed:
Summary by CodeRabbit
New Features
close-menu
events in the navigation menu.clickAction
property for custom actions in menu items.Improvements