Skip to content

Commit cde00df

Browse files
andrewseguintinayuangao
authored andcommitted
feat(sort): fix animation; show on hover (#7608)
1 parent d587abe commit cde00df

File tree

7 files changed

+458
-81
lines changed

7 files changed

+458
-81
lines changed

src/demo-app/table/table-demo.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ <h3>MatTable With MatTableDataSource Example</h3>
235235
selected
236236
</div>
237237

238-
<mat-table [dataSource]="matTableDataSource" [trackBy]="userTrackBy" matSort
238+
<mat-table [dataSource]="matTableDataSource" [trackBy]="userTrackBy"
239+
matSort matSortActive="progress" matSortDirection="asc"
239240
#sortForDataSource="matSort">
240241

241242
<!-- Checkbox Column -->

src/demo-app/table/table-demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class TableDemo {
4343
displayedColumns: UserProperties[] = [];
4444
trackByStrategy: TrackByStrategy = 'reference';
4545
changeReferences = false;
46-
progressSortingDisabled = false;
46+
progressSortingDisabled = true;
4747
highlights = new Set<string>();
4848
wasExpanded = new Set<UserData>();
4949

src/lib/sort/sort-animations.ts

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
transition,
1313
trigger,
1414
keyframes,
15-
AnimationTriggerMetadata,
15+
AnimationTriggerMetadata, query, animateChild,
1616
} from '@angular/animations';
1717
import {AnimationCurves, AnimationDurations} from '@angular/material/core';
1818

@@ -24,47 +24,87 @@ export const matSortAnimations: {
2424
readonly indicator: AnimationTriggerMetadata;
2525
readonly leftPointer: AnimationTriggerMetadata;
2626
readonly rightPointer: AnimationTriggerMetadata;
27-
readonly indicatorToggle: AnimationTriggerMetadata;
27+
readonly arrowOpacity: AnimationTriggerMetadata;
28+
readonly arrowPosition: AnimationTriggerMetadata;
29+
readonly allowChildren: AnimationTriggerMetadata;
2830
} = {
2931
/** Animation that moves the sort indicator. */
3032
indicator: trigger('indicator', [
31-
state('asc', style({transform: 'translateY(0px)'})),
33+
state('active-asc, asc', style({transform: 'translateY(0px)'})),
3234
// 10px is the height of the sort indicator, minus the width of the pointers
33-
state('desc', style({transform: 'translateY(10px)'})),
34-
transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION))
35+
state('active-desc, desc', style({transform: 'translateY(10px)'})),
36+
transition('active-asc <=> active-desc', animate(SORT_ANIMATION_TRANSITION))
3537
]),
3638

3739
/** Animation that rotates the left pointer of the indicator based on the sorting direction. */
3840
leftPointer: trigger('leftPointer', [
39-
state('asc', style({transform: 'rotate(-45deg)'})),
40-
state('desc', style({transform: 'rotate(45deg)'})),
41-
transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION))
41+
state('active-asc, asc', style({transform: 'rotate(-45deg)'})),
42+
state('active-desc, desc', style({transform: 'rotate(45deg)'})),
43+
transition('active-asc <=> active-desc', animate(SORT_ANIMATION_TRANSITION))
4244
]),
4345

4446
/** Animation that rotates the right pointer of the indicator based on the sorting direction. */
4547
rightPointer: trigger('rightPointer', [
46-
state('asc', style({transform: 'rotate(45deg)'})),
47-
state('desc', style({transform: 'rotate(-45deg)'})),
48-
transition('asc <=> desc', animate(SORT_ANIMATION_TRANSITION))
48+
state('active-asc, asc', style({transform: 'rotate(45deg)'})),
49+
state('active-desc, desc', style({transform: 'rotate(-45deg)'})),
50+
transition('active-asc <=> active-desc', animate(SORT_ANIMATION_TRANSITION))
4951
]),
5052

51-
/** Animation that moves the indicator in and out of view when sorting is enabled/disabled. */
52-
indicatorToggle: trigger('indicatorToggle', [
53-
transition('void => asc', animate(SORT_ANIMATION_TRANSITION, keyframes([
54-
style({transform: 'translateY(25%)', opacity: 0}),
55-
style({transform: 'none', opacity: 1})
56-
]))),
57-
transition('asc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([
58-
style({transform: 'none', opacity: 1}),
59-
style({transform: 'translateY(-25%)', opacity: 0})
60-
]))),
61-
transition('void => desc', animate(SORT_ANIMATION_TRANSITION, keyframes([
62-
style({transform: 'translateY(-25%)', opacity: 0}),
63-
style({transform: 'none', opacity: 1})
64-
]))),
65-
transition('desc => void', animate(SORT_ANIMATION_TRANSITION, keyframes([
66-
style({transform: 'none', opacity: 1}),
67-
style({transform: 'translateY(25%)', opacity: 0})
68-
]))),
69-
])
53+
/** Animation that controls the arrow opacity. */
54+
arrowOpacity: trigger('arrowOpacity', [
55+
state('desc-to-active, asc-to-active, active', style({opacity: 1})),
56+
state('desc-to-hint, asc-to-hint, hint', style({opacity: .54})),
57+
state('hint-to-desc, active-to-desc, desc, hint-to-asc, active-to-asc, asc',
58+
style({opacity: 0})),
59+
// Transition between all states except for immediate transitions
60+
transition('* => asc, * => desc, * => active, * => hint', animate('0ms')),
61+
transition('* <=> *', animate(SORT_ANIMATION_TRANSITION))
62+
]),
63+
64+
/**
65+
* Animation for the translation of the arrow as a whole. States are separated into two
66+
* groups: ones with animations and others that are immediate. Immediate states are asc, desc,
67+
* peek, and active. The other states define a specific animation (source-to-destination)
68+
* and are determined as a function of their prev user-perceived state and what the next state
69+
* should be.
70+
*/
71+
arrowPosition: trigger('arrowPosition', [
72+
// Hidden Above => Hint Center
73+
transition('* => desc-to-hint, * => desc-to-active',
74+
animate(SORT_ANIMATION_TRANSITION, keyframes([
75+
style({transform: 'translateY(-25%)'}),
76+
style({transform: 'translateY(0)'})
77+
]))),
78+
// Hint Center => Hidden Below
79+
transition('* => hint-to-desc, * => active-to-desc',
80+
animate(SORT_ANIMATION_TRANSITION, keyframes([
81+
style({transform: 'translateY(0)'}),
82+
style({transform: 'translateY(25%)'})
83+
]))),
84+
// Hidden Below => Hint Center
85+
transition('* => asc-to-hint, * => asc-to-active',
86+
animate(SORT_ANIMATION_TRANSITION, keyframes([
87+
style({transform: 'translateY(25%)'}),
88+
style({transform: 'translateY(0)'})
89+
]))),
90+
// Hint Center => Hidden Above
91+
transition('* => hint-to-asc, * => active-to-asc',
92+
animate(SORT_ANIMATION_TRANSITION, keyframes([
93+
style({transform: 'translateY(0)'}),
94+
style({transform: 'translateY(-25%)'})
95+
]))),
96+
state('desc-to-hint, asc-to-hint, hint, desc-to-active, asc-to-active, active',
97+
style({transform: 'translateY(0)'})),
98+
state('hint-to-desc, active-to-desc, desc',
99+
style({transform: 'translateY(-25%)'})),
100+
state('hint-to-asc, active-to-asc, asc',
101+
style({transform: 'translateY(25%)'})),
102+
]),
103+
104+
/** Necessary trigger that calls animate on children animations. */
105+
allowChildren: trigger('allowChildren', [
106+
transition('* <=> *', [
107+
query('@*', animateChild(), {optional: true})
108+
])
109+
]),
70110
};

src/lib/sort/sort-header.html

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
<div class="mat-sort-header-container"
2+
[class.mat-sort-header-sorted]="_isSorted()"
23
[class.mat-sort-header-position-before]="arrowPosition == 'before'">
34
<button class="mat-sort-header-button" type="button"
5+
[attr.disabled]="_isDisabled() || null"
46
[attr.aria-label]="_intl.sortButtonLabel(id)"
5-
[attr.disabled]="_isDisabled() || null">
7+
(focus)="_setIndicatorHintVisible(true)"
8+
(blur)="_setIndicatorHintVisible(false)">
69
<ng-content></ng-content>
710
</button>
811

9-
<div *ngIf="_isSorted()" class="mat-sort-header-arrow" [@indicatorToggle]="_sort.direction">
12+
<!-- Disable animations while a current animation is running -->
13+
<div class="mat-sort-header-arrow"
14+
[@arrowOpacity]="_getArrowViewState()"
15+
[@arrowPosition]="_getArrowViewState()"
16+
[@allowChildren]="_getArrowDirectionState()"
17+
(@arrowPosition.start)="_disableViewStateAnimation = true"
18+
(@arrowPosition.done)="_disableViewStateAnimation = false">
1019
<div class="mat-sort-header-stem"></div>
11-
<div class="mat-sort-header-indicator" [@indicator]="_sort.direction" >
12-
<div class="mat-sort-header-pointer-left" [@leftPointer]="_sort.direction"></div>
13-
<div class="mat-sort-header-pointer-right" [@rightPointer]="_sort.direction"></div>
20+
<div class="mat-sort-header-indicator" [@indicator]="_getArrowDirectionState()">
21+
<div class="mat-sort-header-pointer-left" [@leftPointer]="_getArrowDirectionState()"></div>
22+
<div class="mat-sort-header-pointer-right" [@rightPointer]="_getArrowDirectionState()"></div>
1423
<div class="mat-sort-header-pointer-middle"></div>
1524
</div>
1625
</div>

src/lib/sort/sort-header.scss

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ $mat-sort-header-arrow-container-size: 12px;
33
$mat-sort-header-arrow-stem-size: 10px;
44
$mat-sort-header-arrow-pointer-length: 6px;
55
$mat-sort-header-arrow-thickness: 2px;
6-
$mat-sort-header-arrow-transition: 225ms cubic-bezier(0.4, 0, 0.2, 1);
6+
$mat-sort-header-arrow-hint-opacity: 0.38;
77

88
.mat-sort-header-container {
99
display: flex;
@@ -60,7 +60,6 @@ $mat-sort-header-arrow-transition: 225ms cubic-bezier(0.4, 0, 0.2, 1);
6060
position: absolute;
6161
top: 0;
6262
left: 0;
63-
transition: $mat-sort-header-arrow-transition;
6463
}
6564

6665
.mat-sort-header-pointer-middle {
@@ -76,7 +75,6 @@ $mat-sort-header-arrow-transition: 225ms cubic-bezier(0.4, 0, 0.2, 1);
7675
background: currentColor;
7776
width: $mat-sort-header-arrow-pointer-length;
7877
height: $mat-sort-header-arrow-thickness;
79-
transition: $mat-sort-header-arrow-transition;
8078
position: absolute;
8179
top: 0;
8280
}

0 commit comments

Comments
 (0)