-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add support for long press to MenuTrigger #780 #789
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
Add support for long press to MenuTrigger #780 #789
Conversation
|
Hi @devongovett, just signed the CLA and pushed lint fixes 😅 . Let me know if there are any changes needed. |
snowystinger
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.
Thanks for working on this, great work so far :) couple of notes on the tests.
| triggerPress(button); | ||
| } else { | ||
| act(() => { | ||
| fireEvent.keyDown(button, {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 believe fireEvent will already wrap in an act, you should just be able to wrap the runAllTimers in it. Followup to that statement, is this runAllTimers needed?
| jest.runAllTimers(); |
Can we get a keyUp event as well, after the timer? that way we are more like real behavior in the browser
These aren't quite testing longPress, we're running all timers, which is the same thing we did for all the previous non-longPress tests. I think we should change it up a bit and only run the timers as far as we need, or we need to verify how far we advanced in time.
We don't need the
it.each syntax, we only have one line in it.
Same comments for the following tests
devongovett
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.
Great start! Left a few suggestions. 😄
| * @param state - State for the menu trigger. | ||
| */ | ||
| export function useMenuTrigger(props: MenuTriggerAriaProps, state: MenuTriggerState, ref: RefObject<HTMLElement>): MenuTriggerAria { | ||
| export function useMenuTrigger(props: MenuTriggerAriaProps, state: MenuTriggerState, ref: RefObject<HTMLElement>, trigger?: MenuTriggerType): MenuTriggerAria { |
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 the trigger argument should be moved to a property of the props object.
| // Portions of the code in this file are based on code from react. | ||
| // Original licensing for the following can be found in the | ||
| // NOTICE file in the root directory of this source tree. | ||
| // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions |
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 don't think this comment is necessary. There's no useLongPress hook in react-interactions as far as I can tell.
|
|
||
| let {pressProps} = usePress({ | ||
| onPressStart(e) { | ||
| timeRef.current = setTimeout(() => { |
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 we should only handle long press events for touch and mouse pointer types. Right now I noticed you can press and hold the enter or space keys on the keyboard as well. You could add a check here for e.pointerType === 'mouse' || e.ponterType === 'touch'.
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 agree with @devongovett, Enter and Space keys are tricky for a longPress on a menu trigger that opens a menu and sets focus to the first menuitem, because the keyup event might also trigger selection on the menuitem that received focus.
| }, | ||
| onKeyDown | ||
| const longPressProps = useLongPress({ | ||
| onLongPress(e) { |
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 you make the change above and only allow mouse and touch pointer types for long presses, you could always call state.toggle('first') here.
| if (trigger === 'longPress') { | ||
| menuTriggerProps = mergeProps(menuTriggerProps, longPressProps, {onKeyDown}); | ||
| } else { | ||
| menuTriggerProps = mergeProps(menuTriggerProps, pressProps, {onKeyDown}); | ||
| } |
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 (trigger === 'longPress') { | |
| menuTriggerProps = mergeProps(menuTriggerProps, longPressProps, {onKeyDown}); | |
| } else { | |
| menuTriggerProps = mergeProps(menuTriggerProps, pressProps, {onKeyDown}); | |
| } | |
| menuTriggerProps = mergeProps(menuTriggerProps, trigger === 'longPress' ? longPressProps : pressProps, {onKeyDown}); |
|
@intergalacticspacehighway one other thing that's a bit tricky: I noticed that the @majornista what's the best way to indicate to screen readers that a long press action is available? VoiceOver still reads that the button has a popup, but I guess we should indicate that there's both a primary click action as well as a long press action. Double tap and hold seems to work to activate the menu. Is there a pattern here that we should follow? |
|
@devongovett and @intergalacticspacehighway, I'm not sure there is a "best way" to indicate to screen readers that a long press action is available, particularly for mobile screen reader users. MenuTrigger already provides the cc @jnurthen |
@devongovett The onPress event is fired as it's passed in the ActionButton as a prop in the story book example. I think someone might pass it deliberately. Do you think we should prevent it? |
|
Yeah I think we can move forward without fixing that issue and we can think about it more after this PR is merged. |
| }, | ||
| "dependencies": { | ||
| "@babel/runtime": "^7.6.2", | ||
| "@react-aria/interactions": "3.1.0", |
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.
Created a constant in useLongPress for long press threshold which is used in MenuTrigger test-case
| const longPressProps = useLongPress({ | ||
| // Close on press start as menu can be in a open state after onLongPress. | ||
| onPressStart() { | ||
| state.close(); |
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.
Recent changes for fixing #925 updated the behaviour of useOverlay. Earlier, onBlurWithin used to get called which calls onClose but now the toggle is only handled by onPressStart from pressProps. (For trigger buttons)
To replicate a similar behavior, I added state.close here. Let me know if it can be done in a better way.
|
Thanks for getting this started. Most of this code was pulled into other PRs done by the team. |
Closes
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project:
None