Skip to content

Commit 8eb1904

Browse files
committed
fix(material/tabs): switch away from animations module
Reworks the tabs so they don't depend on the animations module anymore. This is both simpler and avoids some of the pitfalls of the animations module.
1 parent a11b03b commit 8eb1904

File tree

10 files changed

+238
-236
lines changed

10 files changed

+238
-236
lines changed

src/material/tabs/tab-body.html

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
<div class="mat-mdc-tab-body-content" #content
2-
[@translateTab]="{
3-
value: _position,
4-
params: {animationDuration: animationDuration}
5-
}"
6-
(@translateTab.start)="_onTranslateTabStarted($event)"
7-
(@translateTab.done)="_translateTabComplete.next($event)"
8-
cdkScrollable>
1+
<div
2+
class="mat-mdc-tab-body-content"
3+
#content
4+
cdkScrollable
5+
[class.mat-tab-body-content-left]="_position === 'left'"
6+
[class.mat-tab-body-content-right]="_position === 'right'"
7+
[class.mat-tab-body-content-can-animate]="_position === 'center' || _previousPosition === 'center'">
98
<ng-template matTabBodyHost></ng-template>
109
</div>

src/material/tabs/tab-body.scss

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,33 @@
2727
.mat-mdc-tab-body-content {
2828
height: 100%;
2929
overflow: auto;
30+
transform: none;
31+
visibility: hidden;
32+
33+
.mat-tab-body-animating > &,
34+
.mat-mdc-tab-body-active > & {
35+
visibility: visible;
36+
}
3037

3138
.mat-mdc-tab-group-dynamic-height & {
3239
overflow: hidden;
3340
}
41+
}
42+
43+
.mat-tab-body-content-can-animate {
44+
// Note: there's a 1ms delay so that transition events
45+
// still fire even if the duration is set to zero.
46+
transition: transform var(--mat-tab-animation-duration) 1ms cubic-bezier(0.35, 0, 0.25, 1);
3447

35-
// Usually the `visibility: hidden` added by the animation is enough to prevent focus from
36-
// entering the collapsed content, but children with their own `visibility` can override it.
37-
// This is a fallback that completely hides the content when the element becomes hidden.
38-
// Note that we can't do this in the animation definition, because the style gets recomputed too
39-
// late, breaking the animation because Angular didn't have time to figure out the target height.
40-
// This can also be achieved with JS, but it has issues when starting an animation before
41-
// the previous one has finished.
42-
&[style*='visibility: hidden'] {
43-
display: none;
48+
.mat-mdc-tab-body-wrapper._mat-animation-noopable & {
49+
transition: none;
4450
}
4551
}
52+
53+
.mat-tab-body-content-left {
54+
transform: translate3d(-100%, 0, 0);
55+
}
56+
57+
.mat-tab-body-content-right {
58+
transform: translate3d(100%, 0, 0);
59+
}

src/material/tabs/tab-body.spec.ts

Lines changed: 6 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -36,74 +36,12 @@ describe('MatTabBody', () => {
3636
});
3737
}));
3838

39-
describe('when initialized as center', () => {
40-
let fixture: ComponentFixture<SimpleTabBodyApp>;
41-
42-
it('should be center position if origin is unchanged', () => {
43-
fixture = TestBed.createComponent(SimpleTabBodyApp);
44-
fixture.componentInstance.position = 0;
45-
fixture.detectChanges();
46-
47-
expect(fixture.componentInstance.tabBody._position).toBe('center');
48-
});
49-
50-
it('should be center position if origin is explicitly set to null', () => {
51-
fixture = TestBed.createComponent(SimpleTabBodyApp);
52-
fixture.componentInstance.position = 0;
53-
54-
// It can happen that the `origin` is explicitly set to null through the Angular input
55-
// binding. This test should ensure that the body does properly such origin value.
56-
// The `MatTab` class sets the origin by default to null. See related issue: #12455
57-
fixture.componentInstance.origin = null;
58-
fixture.detectChanges();
59-
60-
expect(fixture.componentInstance.tabBody._position).toBe('center');
61-
});
62-
63-
describe('in LTR direction', () => {
64-
beforeEach(() => {
65-
dir = 'ltr';
66-
fixture = TestBed.createComponent(SimpleTabBodyApp);
67-
});
68-
it('should be left-origin-center position with negative or zero origin', () => {
69-
fixture.componentInstance.position = 0;
70-
fixture.componentInstance.origin = 0;
71-
fixture.detectChanges();
72-
73-
expect(fixture.componentInstance.tabBody._position).toBe('left-origin-center');
74-
});
75-
76-
it('should be right-origin-center position with positive nonzero origin', () => {
77-
fixture.componentInstance.position = 0;
78-
fixture.componentInstance.origin = 1;
79-
fixture.detectChanges();
80-
81-
expect(fixture.componentInstance.tabBody._position).toBe('right-origin-center');
82-
});
83-
});
84-
85-
describe('in RTL direction', () => {
86-
beforeEach(() => {
87-
dir = 'rtl';
88-
fixture = TestBed.createComponent(SimpleTabBodyApp);
89-
});
90-
91-
it('should be right-origin-center position with negative or zero origin', () => {
92-
fixture.componentInstance.position = 0;
93-
fixture.componentInstance.origin = 0;
94-
fixture.detectChanges();
95-
96-
expect(fixture.componentInstance.tabBody._position).toBe('right-origin-center');
97-
});
98-
99-
it('should be left-origin-center position with positive nonzero origin', () => {
100-
fixture.componentInstance.position = 0;
101-
fixture.componentInstance.origin = 1;
102-
fixture.detectChanges();
39+
it('should be center position if origin is unchanged', () => {
40+
const fixture = TestBed.createComponent(SimpleTabBodyApp);
41+
fixture.componentInstance.position = 0;
42+
fixture.detectChanges();
10343

104-
expect(fixture.componentInstance.tabBody._position).toBe('left-origin-center');
105-
});
106-
});
44+
expect(fixture.componentInstance.tabBody._position).toBe('center');
10745
});
10846

10947
describe('should properly set the position in LTR', () => {
@@ -213,14 +151,13 @@ describe('MatTabBody', () => {
213151
@Component({
214152
template: `
215153
<ng-template>Tab Body Content</ng-template>
216-
<mat-tab-body [content]="content()" [position]="position" [origin]="origin"></mat-tab-body>
154+
<mat-tab-body [content]="content()" [position]="position"></mat-tab-body>
217155
`,
218156
imports: [PortalModule, MatRippleModule, MatTabBody],
219157
})
220158
class SimpleTabBodyApp implements AfterViewInit {
221159
content = signal<TemplatePortal | undefined>(undefined);
222160
position: number;
223-
origin: number | null;
224161

225162
@ViewChild(MatTabBody) tabBody: MatTabBody;
226163
@ViewChild(TemplateRef) template: TemplateRef<any>;

0 commit comments

Comments
 (0)