Skip to content

Commit 5063e5c

Browse files
devversionandrewseguin
authored andcommitted
refactor: add support density scaling in the expansion panel
Note: This commit is intentionally not marked as a feature because density styles for the expansion panel are not public API yet: Adds support for density scaling to the Angular Material expansion panel. To be able to add support for density, the panel header animation had to be reworked to be CSS based. The existing inputs for setting collapsed/expanded height still work as expected, but will not respect density. * chore: fix buildifier formatting due to update fix: unable to set expanded or collapsed height in expansion panel (#19322) For the density system, we reworked the expansion panel to no longer rely on Angular animations. Looks like the refactoring missed that units are already set for the `expandedHeight` and `collapsedHeight` inputs. This hasn't been catched in any unit test, so tests are updated to catch this now.
1 parent f0e66de commit 5063e5c

File tree

12 files changed

+81
-66
lines changed

12 files changed

+81
-66
lines changed

src/material-experimental/mdc-color/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package(default_visibility = ["//visibility:public"])
2-
31
load("//tools:defaults.bzl", "sass_library")
42

3+
package(default_visibility = ["//visibility:public"])
4+
55
sass_library(
66
name = "all_color",
77
srcs = ["_all-color.scss"],

src/material-experimental/mdc-density/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package(default_visibility = ["//visibility:public"])
2-
31
load("//tools:defaults.bzl", "sass_library")
42

3+
package(default_visibility = ["//visibility:public"])
4+
55
sass_library(
66
name = "all_density",
77
srcs = ["_all-density.scss"],

src/material/core/density/_index.scss

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// Taken from mat-density with small modifications to not rely on the new Sass module system.
1+
// Taken from mat-density with small modifications to not rely on the new Sass module
2+
// system, and to support arbitrary properties in a density configuration.
23
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-density
34

45
$_mat-density-interval: 4px !default;
56
$_mat-density-minimum-scale: minimum !default;
67
$_mat-density-maximum-scale: maximum !default;
78
$_mat-density-supported-scales: (default, minimum, maximum) !default;
8-
$_mat-density-supported-properties: (height, size) !default;
99
$_mat-density-default-scale: 0 !default;
1010

1111
@function _mat-density-prop-value($density-config, $density-scale, $property-name) {
@@ -15,11 +15,6 @@ $_mat-density-default-scale: 0 !default;
1515
'but received #{$density-scale}.';
1616
}
1717

18-
@if (index($list: $_mat-density-supported-properties, $value: $property-name) == null) {
19-
@error 'mat-density: Supported density properties #{$_mat-density-supported-properties},' +
20-
'but received #{$property-name}.';
21-
}
22-
2318
$value: null;
2419
$property-scale-map: map_get($density-config, $property-name);
2520

src/material/core/theming/tests/BUILD.bazel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package(default_visibility = ["//visibility:public"])
2-
31
load("//tools:defaults.bzl", "sass_binary", "sass_library")
42

3+
package(default_visibility = ["//visibility:public"])
4+
55
# Test theme used to ensure that our themes will compile using CSS variables in
66
# the palettes.
77
sass_binary(

src/material/expansion/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ sass_binary(
5656
sass_binary(
5757
name = "expansion_panel_header_scss",
5858
src = "expansion-panel-header.scss",
59+
deps = [":expansion_scss_lib"],
5960
)
6061

6162
ng_test_library(

src/material/expansion/_expansion-theme.scss

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
@import '../core/density/index';
12
@import '../core/theming/palette';
23
@import '../core/theming/theming';
34
@import '../core/style/elevation';
45
@import '../core/typography/typography-utils';
6+
@import './expansion-variables';
57

68
@mixin mat-expansion-panel-color($config) {
79
$background: map-get($config, background);
@@ -69,7 +71,20 @@
6971
}
7072
}
7173

72-
@mixin _mat-expansion-panel-density($density-scale) {}
74+
@mixin _mat-expansion-panel-density($density-scale) {
75+
$expanded-height: _mat-density-prop-value(
76+
$mat-expansion-panel-header-density-config, $density-scale, expanded-height);
77+
$collapsed-height: _mat-density-prop-value(
78+
$mat-expansion-panel-header-density-config, $density-scale, collapsed-height);
79+
80+
.mat-expansion-panel-header {
81+
height: $collapsed-height;
82+
83+
&.mat-expanded {
84+
height: $expanded-height;
85+
}
86+
}
87+
}
7388

7489
@mixin mat-expansion-panel-theme($theme) {
7590
$color: mat-get-color-config($theme);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Default minimum and maximum height for collapsed panel headers.
2+
$mat-expansion-panel-header-collapsed-height: 48px !default;
3+
$mat-expansion-panel-header-collapsed-minimum-height: 36px !default;
4+
$mat-expansion-panel-header-collapsed-maximum-height:
5+
$mat-expansion-panel-header-collapsed-height !default;
6+
7+
// Default minimum and maximum height for expanded panel headers.
8+
$mat-expansion-panel-header-expanded-height: 64px !default;
9+
$mat-expansion-panel-header-expanded-minimum-height: 48px !default;
10+
$mat-expansion-panel-header-expanded-maximum-height:
11+
$mat-expansion-panel-header-expanded-height !default;
12+
13+
// Density configuration for the expansion panel. Captures the
14+
// height for both expanded and collapsed panel headers.
15+
$mat-expansion-panel-header-density-config: (
16+
collapsed-height: (
17+
default: $mat-expansion-panel-header-collapsed-height,
18+
maximum: $mat-expansion-panel-header-collapsed-maximum-height,
19+
minimum: $mat-expansion-panel-header-collapsed-minimum-height,
20+
),
21+
expanded-height: (
22+
default: $mat-expansion-panel-header-expanded-height,
23+
maximum: $mat-expansion-panel-header-expanded-maximum-height,
24+
minimum: $mat-expansion-panel-header-expanded-minimum-height,
25+
)
26+
) !default;
27+
28+
// Note: Keep this in sync with the animation timing for the toggle indicator
29+
// and body expansion. These are animated using Angular animations.
30+
$mat-expansion-panel-header-transition: 225ms cubic-bezier(0.4, 0, 0.2, 1);

src/material/expansion/expansion-animations.ts

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
*/
88
import {
99
animate,
10-
animateChild,
11-
group,
10+
AnimationTriggerMetadata,
1211
state,
1312
style,
1413
transition,
1514
trigger,
16-
query,
17-
AnimationTriggerMetadata,
1815
} from '@angular/animations';
1916

2017
/** Time and timing curve for expansion panel animations. */
18+
// Note: Keep this in sync with the Sass variable for the panel header animation.
2119
export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,1)';
2220

2321
/**
@@ -44,7 +42,6 @@ export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,
4442
*/
4543
export const matExpansionAnimations: {
4644
readonly indicatorRotate: AnimationTriggerMetadata;
47-
readonly expansionHeaderHeight: AnimationTriggerMetadata;
4845
readonly bodyExpansion: AnimationTriggerMetadata;
4946
} = {
5047
/** Animation that rotates the indicator arrow. */
@@ -54,25 +51,6 @@ export const matExpansionAnimations: {
5451
transition('expanded <=> collapsed, void => collapsed',
5552
animate(EXPANSION_PANEL_ANIMATION_TIMING)),
5653
]),
57-
58-
/** Animation that expands and collapses the panel header height. */
59-
expansionHeaderHeight: trigger('expansionHeight', [
60-
state('collapsed, void', style({
61-
height: '{{collapsedHeight}}',
62-
}), {
63-
params: {collapsedHeight: '48px'},
64-
}),
65-
state('expanded', style({
66-
height: '{{expandedHeight}}'
67-
}), {
68-
params: {expandedHeight: '64px'}
69-
}),
70-
transition('expanded <=> collapsed, void => collapsed', group([
71-
query('@indicatorRotate', animateChild(), {optional: true}),
72-
animate(EXPANSION_PANEL_ANIMATION_TIMING),
73-
])),
74-
]),
75-
7654
/** Animation that expands and collapses the panel content. */
7755
bodyExpansion: trigger('bodyExpansion', [
7856
state('collapsed, void', style({height: '0px', visibility: 'hidden'})),

src/material/expansion/expansion-panel-header.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
@import './expansion-variables';
2+
13
.mat-expansion-panel-header {
24
display: flex;
35
flex-direction: row;
46
align-items: center;
57
padding: 0 24px;
68
border-radius: inherit;
79
position: relative; // Necessary for the strong focus indication.
10+
transition: height $mat-expansion-panel-header-transition;
811

912
&:focus,
1013
&:hover {

src/material/expansion/expansion-panel-header.ts

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import {MatAccordionTogglePosition} from './accordion-base';
4545
changeDetection: ChangeDetectionStrategy.OnPush,
4646
animations: [
4747
matExpansionAnimations.indicatorRotate,
48-
matExpansionAnimations.expansionHeaderHeight
4948
],
5049
host: {
5150
'class': 'mat-expansion-panel-header mat-focus-indicator',
@@ -58,25 +57,14 @@ import {MatAccordionTogglePosition} from './accordion-base';
5857
'[class.mat-expanded]': '_isExpanded()',
5958
'[class.mat-expansion-toggle-indicator-after]': `_getTogglePosition() === 'after'`,
6059
'[class.mat-expansion-toggle-indicator-before]': `_getTogglePosition() === 'before'`,
60+
'[style.height]': '_getHeaderHeight()',
6161
'(click)': '_toggle()',
6262
'(keydown)': '_keydown($event)',
63-
'[@.disabled]': '_animationsDisabled',
64-
'(@expansionHeight.start)': '_animationStarted()',
65-
'[@expansionHeight]': `{
66-
value: _getExpandedState(),
67-
params: {
68-
collapsedHeight: collapsedHeight,
69-
expandedHeight: expandedHeight
70-
}
71-
}`,
7263
},
7364
})
7465
export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
7566
private _parentChangeSubscription = Subscription.EMPTY;
7667

77-
/** Whether Angular animations in the panel header should be disabled. */
78-
_animationsDisabled = true;
79-
8068
constructor(
8169
@Host() public panel: MatExpansionPanel,
8270
private _element: ElementRef,
@@ -120,18 +108,6 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
120108
}
121109
}
122110

123-
_animationStarted() {
124-
// Currently the `expansionHeight` animation has a `void => collapsed` transition which is
125-
// there to work around a bug in Angular (see #13088), however this introduces a different
126-
// issue. The new transition will cause the header to animate in on init (see #16067), if the
127-
// consumer has set a header height that is different from the default one. We work around it
128-
// by disabling animations on the header and re-enabling them after the first animation has run.
129-
// Note that Angular dispatches animation events even if animations are disabled. Ideally this
130-
// wouldn't be necessary if we remove the `void => collapsed` transition, but we have to wait
131-
// for https://github.com/angular/angular/issues/18847 to be resolved.
132-
this._animationsDisabled = false;
133-
}
134-
135111
/** Height of the header while the panel is expanded. */
136112
@Input() expandedHeight: string;
137113

@@ -178,6 +154,20 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
178154
return !this.panel.hideToggle && !this.panel.disabled;
179155
}
180156

157+
/**
158+
* Gets the current height of the header. Null if no custom height has been
159+
* specified, and if the default height from the stylesheet should be used.
160+
*/
161+
_getHeaderHeight(): string|null {
162+
const isExpanded = this._isExpanded();
163+
if (isExpanded && this.expandedHeight) {
164+
return this.expandedHeight;
165+
} else if (!isExpanded && this.collapsedHeight) {
166+
return this.collapsedHeight;
167+
}
168+
return null;
169+
}
170+
181171
/** Handle keydown event calling to toggle() if appropriate. */
182172
_keydown(event: KeyboardEvent) {
183173
switch (event.keyCode) {

src/material/expansion/expansion.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ describe('MatExpansionPanel', () => {
351351
expect(panel.componentInstance.hideToggle).toBe(true);
352352
expect(header.componentInstance.expandedHeight).toBe('10px');
353353
expect(header.componentInstance.collapsedHeight).toBe('16px');
354+
expect(header.nativeElement.style.height).toBe('16px');
355+
356+
fixture.componentInstance.expanded = true;
357+
fixture.detectChanges();
358+
expect(header.nativeElement.style.height).toBe('10px');
354359
});
355360

356361
describe('disabled state', () => {

tools/public_api_guard/material/expansion.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export declare type MatAccordionTogglePosition = 'before' | 'after';
3232

3333
export declare const matExpansionAnimations: {
3434
readonly indicatorRotate: AnimationTriggerMetadata;
35-
readonly expansionHeaderHeight: AnimationTriggerMetadata;
3635
readonly bodyExpansion: AnimationTriggerMetadata;
3736
};
3837

@@ -97,14 +96,13 @@ export declare class MatExpansionPanelDescription {
9796
}
9897

9998
export declare class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
100-
_animationsDisabled: boolean;
10199
collapsedHeight: string;
102100
get disabled(): any;
103101
expandedHeight: string;
104102
panel: MatExpansionPanel;
105103
constructor(panel: MatExpansionPanel, _element: ElementRef, _focusMonitor: FocusMonitor, _changeDetectorRef: ChangeDetectorRef, defaultOptions?: MatExpansionPanelDefaultOptions);
106-
_animationStarted(): void;
107104
_getExpandedState(): string;
105+
_getHeaderHeight(): string | null;
108106
_getPanelId(): string;
109107
_getTogglePosition(): MatAccordionTogglePosition;
110108
_isExpanded(): boolean;

0 commit comments

Comments
 (0)