@@ -38,6 +38,7 @@ import {
3838 SCROLL_THROTTLE_MS ,
3939 TOOLTIP_PANEL_CLASS ,
4040 MAT_TOOLTIP_DEFAULT_OPTIONS ,
41+ TooltipTouchGestures ,
4142} from './index' ;
4243
4344
@@ -895,33 +896,175 @@ describe('MatTooltip', () => {
895896 } ) ) ;
896897 } ) ;
897898
898- describe ( 'special cases' , ( ) => {
899+ describe ( 'touch gestures' , ( ) => {
900+ beforeEach ( ( ) => {
901+ platform . ANDROID = true ;
902+ } ) ;
903+
904+ it ( 'should have a delay when showing on touchstart' , fakeAsync ( ( ) => {
905+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
906+ fixture . detectChanges ( ) ;
907+ const button : HTMLButtonElement = fixture . nativeElement . querySelector ( 'button' ) ;
908+
909+ dispatchFakeEvent ( button , 'touchstart' ) ;
910+ fixture . detectChanges ( ) ;
911+ tick ( 250 ) ; // Halfway through the delay.
912+
913+ assertTooltipInstance ( fixture . componentInstance . tooltip , false ) ;
914+
915+ tick ( 250 ) ; // Finish the delay.
916+ fixture . detectChanges ( ) ;
917+ tick ( 500 ) ; // Finish the animation.
918+
919+ assertTooltipInstance ( fixture . componentInstance . tooltip , true ) ;
920+ } ) ) ;
921+
922+ it ( 'should be able to disable opening on touch' , fakeAsync ( ( ) => {
923+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
924+ fixture . componentInstance . touchGestures = 'off' ;
925+ fixture . detectChanges ( ) ;
926+ const button : HTMLButtonElement = fixture . nativeElement . querySelector ( 'button' ) ;
927+
928+ dispatchFakeEvent ( button , 'touchstart' ) ;
929+ fixture . detectChanges ( ) ;
930+ tick ( 500 ) ; // Finish the delay.
931+ fixture . detectChanges ( ) ;
932+ tick ( 500 ) ; // Finish the animation.
933+
934+ assertTooltipInstance ( fixture . componentInstance . tooltip , false ) ;
935+ } ) ) ;
936+
937+ it ( 'should not prevent the default action on touchstart' , ( ) => {
938+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
939+ fixture . detectChanges ( ) ;
940+ const button : HTMLButtonElement = fixture . nativeElement . querySelector ( 'button' ) ;
941+ const event = dispatchFakeEvent ( button , 'touchstart' ) ;
942+ fixture . detectChanges ( ) ;
943+
944+ expect ( event . defaultPrevented ) . toBe ( false ) ;
945+ } ) ;
946+
947+ it ( 'should close on touchend with a delay' , fakeAsync ( ( ) => {
948+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
949+ fixture . detectChanges ( ) ;
950+ const button : HTMLButtonElement = fixture . nativeElement . querySelector ( 'button' ) ;
951+
952+ dispatchFakeEvent ( button , 'touchstart' ) ;
953+ fixture . detectChanges ( ) ;
954+ tick ( 500 ) ; // Finish the open delay.
955+ fixture . detectChanges ( ) ;
956+ tick ( 500 ) ; // Finish the animation.
957+ assertTooltipInstance ( fixture . componentInstance . tooltip , true ) ;
958+
959+ dispatchFakeEvent ( button , 'touchend' ) ;
960+ fixture . detectChanges ( ) ;
961+ tick ( 1000 ) ; // 2/3 through the delay
962+ assertTooltipInstance ( fixture . componentInstance . tooltip , true ) ;
963+
964+ tick ( 500 ) ; // Finish the delay.
965+ fixture . detectChanges ( ) ;
966+ tick ( 500 ) ; // Finish the exit animation.
899967
900- it ( 'should clear the `user-select` when a tooltip is set on a text field' , ( ) => {
968+ assertTooltipInstance ( fixture . componentInstance . tooltip , false ) ;
969+ } ) ) ;
970+
971+ it ( 'should close on touchcancel with a delay' , fakeAsync ( ( ) => {
972+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
973+ fixture . detectChanges ( ) ;
974+ const button : HTMLButtonElement = fixture . nativeElement . querySelector ( 'button' ) ;
975+
976+ dispatchFakeEvent ( button , 'touchstart' ) ;
977+ fixture . detectChanges ( ) ;
978+ tick ( 500 ) ; // Finish the open delay.
979+ fixture . detectChanges ( ) ;
980+ tick ( 500 ) ; // Finish the animation.
981+ assertTooltipInstance ( fixture . componentInstance . tooltip , true ) ;
982+
983+ dispatchFakeEvent ( button , 'touchcancel' ) ;
984+ fixture . detectChanges ( ) ;
985+ tick ( 1000 ) ; // 2/3 through the delay
986+ assertTooltipInstance ( fixture . componentInstance . tooltip , true ) ;
987+
988+ tick ( 500 ) ; // Finish the delay.
989+ fixture . detectChanges ( ) ;
990+ tick ( 500 ) ; // Finish the exit animation.
991+
992+ assertTooltipInstance ( fixture . componentInstance . tooltip , false ) ;
993+ } ) ) ;
994+
995+ it ( 'should disable native touch interactions' , ( ) => {
996+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
997+ fixture . detectChanges ( ) ;
998+
999+ const styles = fixture . nativeElement . querySelector ( 'button' ) . style ;
1000+ expect ( styles . touchAction || ( styles as any ) . webkitUserDrag ) . toBe ( 'none' ) ;
1001+ } ) ;
1002+
1003+ it ( 'should allow native touch interactions if touch gestures are turned off' , ( ) => {
1004+ const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
1005+ fixture . componentInstance . touchGestures = 'off' ;
1006+ fixture . detectChanges ( ) ;
1007+
1008+ const styles = fixture . nativeElement . querySelector ( 'button' ) . style ;
1009+ expect ( styles . touchAction || ( styles as any ) . webkitUserDrag ) . toBeFalsy ( ) ;
1010+ } ) ;
1011+
1012+ it ( 'should allow text selection on inputs when gestures are set to auto' , ( ) => {
9011013 const fixture = TestBed . createComponent ( TooltipOnTextFields ) ;
902- const instance = fixture . componentInstance ;
1014+ fixture . detectChanges ( ) ;
1015+
1016+ const inputStyle = fixture . componentInstance . input . nativeElement . style ;
1017+ const textareaStyle = fixture . componentInstance . textarea . nativeElement . style ;
1018+
1019+ expect ( inputStyle . userSelect ) . toBeFalsy ( ) ;
1020+ expect ( inputStyle . webkitUserSelect ) . toBeFalsy ( ) ;
1021+ expect ( inputStyle . msUserSelect ) . toBeFalsy ( ) ;
1022+ expect ( ( inputStyle as any ) . MozUserSelect ) . toBeFalsy ( ) ;
1023+
1024+ expect ( textareaStyle . userSelect ) . toBeFalsy ( ) ;
1025+ expect ( textareaStyle . webkitUserSelect ) . toBeFalsy ( ) ;
1026+ expect ( textareaStyle . msUserSelect ) . toBeFalsy ( ) ;
1027+ expect ( ( textareaStyle as any ) . MozUserSelect ) . toBeFalsy ( ) ;
1028+ } ) ;
9031029
1030+ it ( 'should disable text selection on inputs when gestures are set to on' , ( ) => {
1031+ const fixture = TestBed . createComponent ( TooltipOnTextFields ) ;
1032+ fixture . componentInstance . touchGestures = 'on' ;
9041033 fixture . detectChanges ( ) ;
9051034
906- expect ( instance . input . nativeElement . style . userSelect ) . toBeFalsy ( ) ;
907- expect ( instance . input . nativeElement . style . webkitUserSelect ) . toBeFalsy ( ) ;
908- expect ( instance . input . nativeElement . style . msUserSelect ) . toBeFalsy ( ) ;
1035+ const inputStyle = fixture . componentInstance . input . nativeElement . style ;
1036+ const inputUserSelect = inputStyle . userSelect || inputStyle . webkitUserSelect ||
1037+ inputStyle . msUserSelect || ( inputStyle as any ) . MozUserSelect ;
1038+ const textareaStyle = fixture . componentInstance . textarea . nativeElement . style ;
1039+ const textareaUserSelect = textareaStyle . userSelect || textareaStyle . webkitUserSelect ||
1040+ textareaStyle . msUserSelect || ( textareaStyle as any ) . MozUserSelect ;
9091041
910- expect ( instance . textarea . nativeElement . style . userSelect ) . toBeFalsy ( ) ;
911- expect ( instance . textarea . nativeElement . style . webkitUserSelect ) . toBeFalsy ( ) ;
912- expect ( instance . textarea . nativeElement . style . msUserSelect ) . toBeFalsy ( ) ;
1042+ expect ( inputUserSelect ) . toBe ( 'none' ) ;
1043+ expect ( textareaUserSelect ) . toBe ( 'none' ) ;
9131044 } ) ;
9141045
915- it ( 'should clear the `-webkit-user-drag` on draggable elements' , ( ) => {
1046+ it ( 'should allow native dragging on draggable elements when gestures are set to auto ' , ( ) => {
9161047 const fixture = TestBed . createComponent ( TooltipOnDraggableElement ) ;
917-
9181048 fixture . detectChanges ( ) ;
9191049
9201050 expect ( fixture . componentInstance . button . nativeElement . style . webkitUserDrag ) . toBeFalsy ( ) ;
9211051 } ) ;
9221052
1053+ it ( 'should disable native dragging on draggable elements when gestures are set to on' , ( ) => {
1054+ const fixture = TestBed . createComponent ( TooltipOnDraggableElement ) ;
1055+ fixture . componentInstance . touchGestures = 'on' ;
1056+ fixture . detectChanges ( ) ;
1057+
1058+ const styles = fixture . componentInstance . button . nativeElement . style ;
1059+
1060+ if ( 'webkitUserDrag' in styles ) {
1061+ expect ( styles . webkitUserDrag ) . toBe ( 'none' ) ;
1062+ }
1063+ } ) ;
1064+
9231065 it ( 'should not open on `mouseenter` on iOS' , ( ) => {
9241066 platform . IOS = true ;
1067+ platform . ANDROID = false ;
9251068
9261069 const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
9271070
@@ -934,6 +1077,7 @@ describe('MatTooltip', () => {
9341077
9351078 it ( 'should not open on `mouseenter` on Android' , ( ) => {
9361079 platform . ANDROID = true ;
1080+ platform . IOS = false ;
9371081
9381082 const fixture = TestBed . createComponent ( BasicTooltipDemo ) ;
9391083
@@ -943,7 +1087,6 @@ describe('MatTooltip', () => {
9431087
9441088 assertTooltipInstance ( fixture . componentInstance . tooltip , false ) ;
9451089 } ) ;
946-
9471090 } ) ;
9481091
9491092} ) ;
@@ -955,7 +1098,8 @@ describe('MatTooltip', () => {
9551098 *ngIf="showButton"
9561099 [matTooltip]="message"
9571100 [matTooltipPosition]="position"
958- [matTooltipClass]="{'custom-one': showTooltipClass, 'custom-two': showTooltipClass }">
1101+ [matTooltipClass]="{'custom-one': showTooltipClass, 'custom-two': showTooltipClass }"
1102+ [matTooltipTouchGestures]="touchGestures">
9591103 Button
9601104 </button>`
9611105} )
@@ -964,6 +1108,7 @@ class BasicTooltipDemo {
9641108 message : any = initialTooltipMessage ;
9651109 showButton : boolean = true ;
9661110 showTooltipClass = false ;
1111+ touchGestures : TooltipTouchGestures = 'auto' ;
9671112 @ViewChild ( MatTooltip , { static : false } ) tooltip : MatTooltip ;
9681113 @ViewChild ( 'button' , { static : false } ) button : ElementRef < HTMLButtonElement > ;
9691114}
@@ -1037,31 +1182,33 @@ class DataBoundAriaLabelTooltip {
10371182 template : `
10381183 <input
10391184 #input
1040- style="user-select: none; -webkit-user-select: none "
1041- matTooltip="Something ">
1185+ matTooltip="Something "
1186+ [matTooltipTouchGestures]="touchGestures ">
10421187
10431188 <textarea
10441189 #textarea
1045- style="user-select: none; -webkit-user-select: none "
1046- matTooltip="Another thing "></textarea>
1190+ matTooltip="Another thing "
1191+ [matTooltipTouchGestures]="touchGestures "></textarea>
10471192 ` ,
10481193} )
10491194class TooltipOnTextFields {
10501195 @ViewChild ( 'input' , { static : false } ) input : ElementRef < HTMLInputElement > ;
10511196 @ViewChild ( 'textarea' , { static : false } ) textarea : ElementRef < HTMLTextAreaElement > ;
1197+ touchGestures : TooltipTouchGestures = 'auto' ;
10521198}
10531199
10541200@Component ( {
10551201 template : `
10561202 <button
10571203 #button
1058- style="-webkit-user-drag: none;"
10591204 draggable="true"
1060- matTooltip="Drag me"></button>
1205+ matTooltip="Drag me"
1206+ [matTooltipTouchGestures]="touchGestures"></button>
10611207 ` ,
10621208} )
10631209class TooltipOnDraggableElement {
10641210 @ViewChild ( 'button' , { static : false } ) button : ElementRef ;
1211+ touchGestures : TooltipTouchGestures = 'auto' ;
10651212}
10661213
10671214@Component ( {
0 commit comments