Skip to content
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

feat(tabs): add swipe events #6294

Closed
wants to merge 36 commits into from
Closed

feat(tabs): add swipe events #6294

wants to merge 36 commits into from

Conversation

amcdnl
Copy link
Contributor

@amcdnl amcdnl commented Aug 5, 2017

Addresses #2209 by adding swipe events to the tab content area.

@amcdnl amcdnl requested a review from jelbourn August 5, 2017 17:05
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Aug 5, 2017
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amcdnl trying this out, it seems like this breaks the ability to scroll the tab content by dragging on mobile
(I just tried on the device emulator in Chrome)

@@ -54,3 +54,12 @@ export interface HammerManager {
off(events: string, handler?: Function): void;
on(events: string, handler: Function): void;
}

/** @docs-private */
export interface HammerEvent {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why introduce this instead of using the existing HammerInput type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not realize those were the same, I'll consolidate.

_bodyContentSwiped(event: HammerEvent): void {
if(this.selectedIndex === null) this.selectedIndex = 0;
if(this.selectedIndex !== 0 && event.type === 'swiperight') {
this.selectedIndex = this._findNextTabByIndex(this.selectedIndex, 'left');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to send left or right instead of directly sending the delta

@@ -1,4 +1,6 @@
<div class="mat-tab-body-content" #content
(swipeleft)="onSwipe.emit($event)"
(swiperight)="onSwipe.emit($event)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not just (swipe)?

if(this.selectedIndex !== 0 && event.type === 'swiperight') {
this.selectedIndex = this._findNextTabByIndex(this.selectedIndex, 'left');
} else if(this.selectedIndex < this._tabs.length && event.type === 'swipeleft') {
this.selectedIndex = this._findNextTabByIndex(this.selectedIndex, 'right');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are left and right reversed in RTL?

@@ -7,6 +7,8 @@
</div>

<div class="mat-tab-label-container" #tabListContainer
(swipeleft)="_handleSwipe($event)"
(swiperight)="_handleSwipe($event)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This captures the swipe gesture specifically, but it feels like the header would need to capture dragging as well (which I think Hammer captures under panmove)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. It has a drag property I listen to.


/** Body content was swiped left/right */
_bodyContentSwiped(event: HammerEvent): void {
if(this.selectedIndex === null) this.selectedIndex = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Braces are always required

const tabsArray = this._tabs.toArray();
const nextIdx = direction === 'right' ? index + 1 : index - 1;

if(nextIdx < tabsArray.length && nextIdx >= 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space between if and paren (here and elsewhere)

@@ -275,4 +275,31 @@ export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit
this._tabBodyWrapperHeight = this._tabBodyWrapper.nativeElement.clientHeight;
this._renderer.setStyle(this._tabBodyWrapper.nativeElement, 'height', '');
}

/** Finds the next tab in the stack for the given direction */
_findNextTabByIndex(index: number, direction: string): number {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amcdnl
Copy link
Contributor Author

amcdnl commented Aug 12, 2017

@jelbourn - I'm getting a lint error saying:

ERROR: /Users/austin/dev/material2/src/lib/tabs/tab-body.ts[30, 73]: 'HammerInput' is declared but never used.

which is false because its being used in the onSwipe event here:

@Output() onSwipe: EventEmitter<HammerInput> = new EventEmitter<HammerInput>();

@amcdnl
Copy link
Contributor Author

amcdnl commented Aug 13, 2017

@jelbourn - ready for review.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the lint error: it's a bug in the version of TypeScript we use. Just need to suppress it until we bump the TS version

Seems good overall, just needs unit tests (the slider has examples of faking hammer events)

@@ -1,4 +1,6 @@
<div class="mat-tab-body-content" #content
(swipe)="onSwipe.emit($event)"
[style.touch-action]="'pan-y'"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment for why this needs to be an inline style? Also, since this is static, you don't need a binding; just style="touch-action: pan-y" is good.

Copy link
Contributor Author

@amcdnl amcdnl Aug 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like the comment to be a HTML inline comment?

This actually doesn't work if you do it static like you suggested. I had tried that at first implementation.

Reference: hammerjs/hammer.js#1014

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent a bit too much time tracking this down. touch-action: none is coming from our material GestureConfig; adding the swipe gesture always sets the touch action to pan-y + pan-x (equivalent to none).

The "correct" fix for this would be to change how our gesture config add recognizers for certain events, but that's more complicated than we want to do right now. I filed #6484 to track this. Can you make your comment something like

<!-- touch-action workaround for https://github.com/angular/material2/issues/6484 -->

Comment can go above the element (I don't think a comment inside of a tag is valid html). HTML comments are stripped when packaging the release

this.selectedIndex = 0;
}

if (event.direction === 2 || event.direction === 4) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an enum or constants instead of using the number literals in the function body

commit 85a6fff
Author: mmalerba <mmalerba@google.com>
Date:   Sat Aug 12 15:05:58 2017 -0700

    fix demo app (angular#6437)
@amcdnl
Copy link
Contributor Author

amcdnl commented Aug 15, 2017

@jelbourn - added unit tests and comments, ready for review again.

@rafaelss95
Copy link
Contributor

rafaelss95 commented Aug 15, 2017

@jelbourn I just searched "enum" in repo and found this (PascalCased enum members) and this (UPPERCASED enum members).

... and the enum members here (from HammerDirection) are going to be lowercased. I'm not sure what's the standard for enums in the repo, but I think the case of enum members should be consistent, shouldn't it?

Note that according this style-guide the recommended approach for enum members is to use PascalCase.

deltaY: number;
center: { x: number; y: number; };
}

/** @docs-private */
export enum HammerDirection {
left = 2,
right = 4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum fields should be PascalCase

@@ -214,6 +219,21 @@ describe('MdTabHeader', () => {
.toBe(0, 'Expected no ripple to show up after mousedown');
});

it('should update scroll to next set on swipe', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next set?

const body = fixture.nativeElement.
querySelector('.mat-tab-body-active .mat-tab-body-content');

dispatchSwipeEvent(body, 2, gestureConfig);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the enum rather than hard-coded numbers


// select the second tab
const body = fixture.nativeElement.
querySelector('.mat-tab-body-active .mat-tab-body-content');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer breaking at the higher syntactic level:

    const body = 
        fixture.nativeElement.querySelector('.mat-tab-body-active .mat-tab-body-content');

@@ -169,6 +176,22 @@ describe('MdTabGroup', () => {
expect(testElement.querySelectorAll('.mat-ripple-element').length)
.toBe(0, 'Expected no ripple to show up on label mousedown.');
});

it('should switch tabs on body swipe', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need tests for skipping disabled tabs and for swipes at the first/last tab.

config.emitEventForElement('swipe', bodyElement, {
deltaX: direction === 2 ? -100 : 100,
direction: direction,
srcEvent: { preventDefault: jasmine.createSpy('preventDefault') }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omit spaces in braces

let direction = event.direction;
if (this._dir.value === 'rtl') {
direction = direction === HammerDirection.left ?
HammerDirection.right : HammerDirection.left;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overflow indent is +4, but this one can also be broken at a higher syntactic level

direction =
    direction === HammerDirection.left ? HammerDirection.right : HammerDirection.left;

@amcdnl
Copy link
Contributor Author

amcdnl commented Aug 16, 2017

@jelbourn - rdy to go.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @andrewseguin should also take a look

@andrewseguin
Copy link
Contributor

Looks good to me as well, thanks for adding this!

@jelbourn
Copy link
Member

Maybe a flake? Try rebasing and re-pushing?

@CharlBest
Copy link

I was just wondering how it is going with that weird error? Did a little search and found this. Hope it helps. microsoft/TypeScript#14538 (comment)

@josephperrott josephperrott added target: minor This PR is targeted for the next minor release and removed action: merge The PR is ready for merge by the caretaker labels Jun 26, 2018
@CharlBest
Copy link

Hi @amcdnl do you think this PR will make the next minor release?

@amcdnl
Copy link
Contributor Author

amcdnl commented Jul 15, 2018

@CharlBest - That would be a @jelbourn call.

@jelbourn
Copy link
Member

Looks like there are still failures on CI

@CharlBest
Copy link

@amcdnl Do you think the CI failures are difficult to fix?

@CharlBest
Copy link

Any progress on this?

@CharlBest
Copy link

Any progress on this @amcdnl ?

@ngbot
Copy link

ngbot bot commented Aug 20, 2018

Hi @amcdnl! This PR has merge conflicts due to recent upstream merges.
Please help to unblock it by resolving these conflicts. Thanks!

1 similar comment
@ngbot
Copy link

ngbot bot commented Aug 20, 2018

Hi @amcdnl! This PR has merge conflicts due to recent upstream merges.
Please help to unblock it by resolving these conflicts. Thanks!

@CharlBest
Copy link

@amcdnl do you think this will make the v7 release?

@CharlBest
Copy link

@jelbourn Do you think this PR will be considered or is it out of scope at the moment?

@jelbourn
Copy link
Member

Austin has been taking some time off, we'll revisit when he gets back

@CharlBest
Copy link

@jelbourn Thank you for the reply. Good luck with everything you're working on and great job.

@CharlBest
Copy link

@jelbourn It doesn't look like @amcdnl will be working on this or am I wrong? Can I help with this PR? Just think this will give the tabs a nice native feeling.

@andrewseguin
Copy link
Contributor

@CharlBest If you would like to take over on this pull request, then I'd be happy to work with you on reviewing and getting it merged in

@CharlBest
Copy link

CharlBest commented Feb 19, 2019

Hi @andrewseguin

Yes sure. I won't mind doing it although I'm not exactly sure what I'm suppose to do. :)

@mmalerba mmalerba added aaa and removed aaa labels Apr 25, 2019
@ceolinrenato
Copy link

@andrewseguin @CharlBest did you guys took over this pull request? Or is it still stalled?
I'm highly interested in this feature

@jelbourn
Copy link
Member

We decided recently that we want to remove HammerJS as a dependency, so we probably won't add this directly to the library any more, and instead document instructions for how to accomplish it with the gesture library of your choice.

@jelbourn
Copy link
Member

Closing this since we've decided to remove Hammer as a dependency and push gesture recognition to the application layer

@jelbourn jelbourn closed this Jun 13, 2019
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes PR author has agreed to Google's Contributor License Agreement target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet