-
Notifications
You must be signed in to change notification settings - Fork 1
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
PER-8633: Arrow nav #300
PER-8633: Arrow nav #300
Conversation
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 left a few comments on some minor things in the code I'd like changed. In terms of the behavior though, this works great from the testing I did!
} | ||
|
||
public setFocusToInputOrButton(inputClass) { | ||
const input = document.querySelector(`.${inputClass}`); |
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 document
here, I think we can use an ElementRef
type here to get the root element of this component, and then use querySelector
there instead to focus everything. I think that's the more "Angular" way of doing things, and it prevents any logic from this component ever "leaking out" of the component. Even though that should never happen in theory, we should probably guard against it anyway. This should be done in the setFocusToCurrentIndex
method as well.
@@ -269,4 +270,46 @@ export class EditTagsComponent | |||
close() { | |||
this.dialogRef.close(); | |||
} | |||
|
|||
onArrowNav(event: KeyboardEvent, index: number) { | |||
if (event.key === 'ArrowDown') { |
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.
We should probably use event.stopPropagation()
here, so that we don't even have to edit file-viewer.component.ts
at all, as the event gets stopped before it propagates upward to parent components. We should do the same for the setFocusToFirstTagOrButton
method as well.
testIndex | ||
); | ||
|
||
// expect(componentInstance.currentIndex).toBe(testIndex + 1); |
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.
// expect(componentInstance.currentIndex).toBe(testIndex + 1); |
We can probably delete this 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.
I'm not sure if it's possible, but might it be more effective to test if the proper elements are focused in DOM rather than spying on function calls? Sometimes spies are the most effective way to do testing, but I feel like in this situation if we can test focus directly (I think through document.activeElement
... but I could be unsure about that!) it'd be the best because we could refactor the function calls later and still have tests pass. I think testing focus might be tricky though, so if it isn't possible these tests are a good compromise.
@meisekimiu I have implemented the changes you asked for! And wrote the tests! |
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 adding these, I left a small note, but this seems good to me now!
it('should handle ArrowDown event', async () => { | ||
const { instance: componentInstance } = await defaultRender(); | ||
componentInstance.isEditing = true; | ||
|
||
spyOn(componentInstance, 'setFocusToCurrentIndex'); | ||
|
||
const testIndex = 0; | ||
componentInstance.onArrowNav( | ||
new KeyboardEvent('keydown', { key: 'ArrowDown' }), | ||
testIndex | ||
); | ||
|
||
expect(componentInstance.setFocusToCurrentIndex).toHaveBeenCalledWith( | ||
testIndex + 1 | ||
); | ||
}); | ||
|
||
it('should handle ArrowUp event when the first input is highlighted', async () => { | ||
const { instance: componentInstance } = await defaultRender(); | ||
componentInstance.isEditing = true; | ||
|
||
spyOn(componentInstance, 'setFocusToInputOrButton'); | ||
|
||
const testIndex = 0; | ||
componentInstance.onArrowNav( | ||
new KeyboardEvent('keydown', { key: 'ArrowUp' }), | ||
testIndex | ||
); | ||
|
||
expect(componentInstance.setFocusToInputOrButton).toHaveBeenCalledWith( | ||
'new-tag-keyword' | ||
); | ||
}); | ||
|
||
it('should handle ArrowUp event', async () => { | ||
const { instance: componentInstance } = await defaultRender(); | ||
componentInstance.isEditing = true; | ||
|
||
spyOn(componentInstance, 'setFocusToCurrentIndex'); | ||
|
||
const testIndex = 4; | ||
componentInstance.onArrowNav( | ||
new KeyboardEvent('keydown', { key: 'ArrowUp' }), | ||
testIndex | ||
); | ||
|
||
expect(componentInstance.setFocusToCurrentIndex).toHaveBeenCalledWith( | ||
testIndex - 1 | ||
); | ||
}); |
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.
it('should handle ArrowDown event', async () => { | |
const { instance: componentInstance } = await defaultRender(); | |
componentInstance.isEditing = true; | |
spyOn(componentInstance, 'setFocusToCurrentIndex'); | |
const testIndex = 0; | |
componentInstance.onArrowNav( | |
new KeyboardEvent('keydown', { key: 'ArrowDown' }), | |
testIndex | |
); | |
expect(componentInstance.setFocusToCurrentIndex).toHaveBeenCalledWith( | |
testIndex + 1 | |
); | |
}); | |
it('should handle ArrowUp event when the first input is highlighted', async () => { | |
const { instance: componentInstance } = await defaultRender(); | |
componentInstance.isEditing = true; | |
spyOn(componentInstance, 'setFocusToInputOrButton'); | |
const testIndex = 0; | |
componentInstance.onArrowNav( | |
new KeyboardEvent('keydown', { key: 'ArrowUp' }), | |
testIndex | |
); | |
expect(componentInstance.setFocusToInputOrButton).toHaveBeenCalledWith( | |
'new-tag-keyword' | |
); | |
}); | |
it('should handle ArrowUp event', async () => { | |
const { instance: componentInstance } = await defaultRender(); | |
componentInstance.isEditing = true; | |
spyOn(componentInstance, 'setFocusToCurrentIndex'); | |
const testIndex = 4; | |
componentInstance.onArrowNav( | |
new KeyboardEvent('keydown', { key: 'ArrowUp' }), | |
testIndex | |
); | |
expect(componentInstance.setFocusToCurrentIndex).toHaveBeenCalledWith( | |
testIndex - 1 | |
); | |
}); |
I think we can just delete these tests now that the behavior is tested with activeElement
in the below tests! Thanks for writing those tests.
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 great and seems to be working as described!
Allow the user to use the arrows to navigate through tags
f5aecaf
to
48d7df2
Compare
Allow the user to use the arrows to navigate through tags
I have also disabled the navigation with the arrows when the file viewer is open and the tags dialog is showing.
Steps to test:
1.Open the tags in the side bar or the file viewer.
2. Highlight the input with tab or by clicking it.
3. Use the arrows to navigate.