1 | import { CdkAccordionItem, CdkAccordion, CdkAccordionModule } from '@angular/cdk/accordion';
|
---|
2 | import { TemplatePortal, PortalModule } from '@angular/cdk/portal';
|
---|
3 | import { DOCUMENT, CommonModule } from '@angular/common';
|
---|
4 | import { InjectionToken, Directive, TemplateRef, EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, Optional, SkipSelf, Inject, ChangeDetectorRef, ViewContainerRef, Input, Output, ContentChild, ViewChild, Host, ElementRef, Attribute, QueryList, ContentChildren, NgModule } from '@angular/core';
|
---|
5 | import { mixinTabIndex, MatCommonModule } from '@angular/material/core';
|
---|
6 | import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
---|
7 | import { FocusMonitor, FocusKeyManager } from '@angular/cdk/a11y';
|
---|
8 | import { distinctUntilChanged, startWith, filter, take } from 'rxjs/operators';
|
---|
9 | import { ENTER, hasModifierKey, SPACE } from '@angular/cdk/keycodes';
|
---|
10 | import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
|
---|
11 | import { Subject, Subscription, EMPTY, merge } from 'rxjs';
|
---|
12 | import { trigger, state, style, transition, animate } from '@angular/animations';
|
---|
13 | import { UniqueSelectionDispatcher } from '@angular/cdk/collections';
|
---|
14 |
|
---|
15 | /**
|
---|
16 | * @license
|
---|
17 | * Copyright Google LLC All Rights Reserved.
|
---|
18 | *
|
---|
19 | * Use of this source code is governed by an MIT-style license that can be
|
---|
20 | * found in the LICENSE file at https://angular.io/license
|
---|
21 | */
|
---|
22 | /**
|
---|
23 | * Token used to provide a `MatAccordion` to `MatExpansionPanel`.
|
---|
24 | * Used primarily to avoid circular imports between `MatAccordion` and `MatExpansionPanel`.
|
---|
25 | */
|
---|
26 | const MAT_ACCORDION = new InjectionToken('MAT_ACCORDION');
|
---|
27 |
|
---|
28 | /**
|
---|
29 | * @license
|
---|
30 | * Copyright Google LLC All Rights Reserved.
|
---|
31 | *
|
---|
32 | * Use of this source code is governed by an MIT-style license that can be
|
---|
33 | * found in the LICENSE file at https://angular.io/license
|
---|
34 | */
|
---|
35 | /** Time and timing curve for expansion panel animations. */
|
---|
36 | // Note: Keep this in sync with the Sass variable for the panel header animation.
|
---|
37 | const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,1)';
|
---|
38 | /**
|
---|
39 | * Animations used by the Material expansion panel.
|
---|
40 | *
|
---|
41 | * A bug in angular animation's `state` when ViewContainers are moved using ViewContainerRef.move()
|
---|
42 | * causes the animation state of moved components to become `void` upon exit, and not update again
|
---|
43 | * upon reentry into the DOM. This can lead a to situation for the expansion panel where the state
|
---|
44 | * of the panel is `expanded` or `collapsed` but the animation state is `void`.
|
---|
45 | *
|
---|
46 | * To correctly handle animating to the next state, we animate between `void` and `collapsed` which
|
---|
47 | * are defined to have the same styles. Since angular animates from the current styles to the
|
---|
48 | * destination state's style definition, in situations where we are moving from `void`'s styles to
|
---|
49 | * `collapsed` this acts a noop since no style values change.
|
---|
50 | *
|
---|
51 | * In the case where angular's animation state is out of sync with the expansion panel's state, the
|
---|
52 | * expansion panel being `expanded` and angular animations being `void`, the animation from the
|
---|
53 | * `expanded`'s effective styles (though in a `void` animation state) to the collapsed state will
|
---|
54 | * occur as expected.
|
---|
55 | *
|
---|
56 | * Angular Bug: https://github.com/angular/angular/issues/18847
|
---|
57 | *
|
---|
58 | * @docs-private
|
---|
59 | */
|
---|
60 | const matExpansionAnimations = {
|
---|
61 | /** Animation that rotates the indicator arrow. */
|
---|
62 | indicatorRotate: trigger('indicatorRotate', [
|
---|
63 | state('collapsed, void', style({ transform: 'rotate(0deg)' })),
|
---|
64 | state('expanded', style({ transform: 'rotate(180deg)' })),
|
---|
65 | transition('expanded <=> collapsed, void => collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)),
|
---|
66 | ]),
|
---|
67 | /** Animation that expands and collapses the panel content. */
|
---|
68 | bodyExpansion: trigger('bodyExpansion', [
|
---|
69 | state('collapsed, void', style({ height: '0px', visibility: 'hidden' })),
|
---|
70 | state('expanded', style({ height: '*', visibility: 'visible' })),
|
---|
71 | transition('expanded <=> collapsed, void => collapsed', animate(EXPANSION_PANEL_ANIMATION_TIMING)),
|
---|
72 | ])
|
---|
73 | };
|
---|
74 |
|
---|
75 | /**
|
---|
76 | * @license
|
---|
77 | * Copyright Google LLC All Rights Reserved.
|
---|
78 | *
|
---|
79 | * Use of this source code is governed by an MIT-style license that can be
|
---|
80 | * found in the LICENSE file at https://angular.io/license
|
---|
81 | */
|
---|
82 | /**
|
---|
83 | * Expansion panel content that will be rendered lazily
|
---|
84 | * after the panel is opened for the first time.
|
---|
85 | */
|
---|
86 | class MatExpansionPanelContent {
|
---|
87 | constructor(_template) {
|
---|
88 | this._template = _template;
|
---|
89 | }
|
---|
90 | }
|
---|
91 | MatExpansionPanelContent.decorators = [
|
---|
92 | { type: Directive, args: [{
|
---|
93 | selector: 'ng-template[matExpansionPanelContent]'
|
---|
94 | },] }
|
---|
95 | ];
|
---|
96 | MatExpansionPanelContent.ctorParameters = () => [
|
---|
97 | { type: TemplateRef }
|
---|
98 | ];
|
---|
99 |
|
---|
100 | /**
|
---|
101 | * @license
|
---|
102 | * Copyright Google LLC All Rights Reserved.
|
---|
103 | *
|
---|
104 | * Use of this source code is governed by an MIT-style license that can be
|
---|
105 | * found in the LICENSE file at https://angular.io/license
|
---|
106 | */
|
---|
107 | /** Counter for generating unique element ids. */
|
---|
108 | let uniqueId = 0;
|
---|
109 | /**
|
---|
110 | * Injection token that can be used to configure the default
|
---|
111 | * options for the expansion panel component.
|
---|
112 | */
|
---|
113 | const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS = new InjectionToken('MAT_EXPANSION_PANEL_DEFAULT_OPTIONS');
|
---|
114 | const ɵ0 = undefined;
|
---|
115 | /**
|
---|
116 | * This component can be used as a single element to show expandable content, or as one of
|
---|
117 | * multiple children of an element with the MatAccordion directive attached.
|
---|
118 | */
|
---|
119 | class MatExpansionPanel extends CdkAccordionItem {
|
---|
120 | constructor(accordion, _changeDetectorRef, _uniqueSelectionDispatcher, _viewContainerRef, _document, _animationMode, defaultOptions) {
|
---|
121 | super(accordion, _changeDetectorRef, _uniqueSelectionDispatcher);
|
---|
122 | this._viewContainerRef = _viewContainerRef;
|
---|
123 | this._animationMode = _animationMode;
|
---|
124 | this._hideToggle = false;
|
---|
125 | /** An event emitted after the body's expansion animation happens. */
|
---|
126 | this.afterExpand = new EventEmitter();
|
---|
127 | /** An event emitted after the body's collapse animation happens. */
|
---|
128 | this.afterCollapse = new EventEmitter();
|
---|
129 | /** Stream that emits for changes in `@Input` properties. */
|
---|
130 | this._inputChanges = new Subject();
|
---|
131 | /** ID for the associated header element. Used for a11y labelling. */
|
---|
132 | this._headerId = `mat-expansion-panel-header-${uniqueId++}`;
|
---|
133 | /** Stream of body animation done events. */
|
---|
134 | this._bodyAnimationDone = new Subject();
|
---|
135 | this.accordion = accordion;
|
---|
136 | this._document = _document;
|
---|
137 | // We need a Subject with distinctUntilChanged, because the `done` event
|
---|
138 | // fires twice on some browsers. See https://github.com/angular/angular/issues/24084
|
---|
139 | this._bodyAnimationDone.pipe(distinctUntilChanged((x, y) => {
|
---|
140 | return x.fromState === y.fromState && x.toState === y.toState;
|
---|
141 | })).subscribe(event => {
|
---|
142 | if (event.fromState !== 'void') {
|
---|
143 | if (event.toState === 'expanded') {
|
---|
144 | this.afterExpand.emit();
|
---|
145 | }
|
---|
146 | else if (event.toState === 'collapsed') {
|
---|
147 | this.afterCollapse.emit();
|
---|
148 | }
|
---|
149 | }
|
---|
150 | });
|
---|
151 | if (defaultOptions) {
|
---|
152 | this.hideToggle = defaultOptions.hideToggle;
|
---|
153 | }
|
---|
154 | }
|
---|
155 | /** Whether the toggle indicator should be hidden. */
|
---|
156 | get hideToggle() {
|
---|
157 | return this._hideToggle || (this.accordion && this.accordion.hideToggle);
|
---|
158 | }
|
---|
159 | set hideToggle(value) {
|
---|
160 | this._hideToggle = coerceBooleanProperty(value);
|
---|
161 | }
|
---|
162 | /** The position of the expansion indicator. */
|
---|
163 | get togglePosition() {
|
---|
164 | return this._togglePosition || (this.accordion && this.accordion.togglePosition);
|
---|
165 | }
|
---|
166 | set togglePosition(value) {
|
---|
167 | this._togglePosition = value;
|
---|
168 | }
|
---|
169 | /** Determines whether the expansion panel should have spacing between it and its siblings. */
|
---|
170 | _hasSpacing() {
|
---|
171 | if (this.accordion) {
|
---|
172 | return this.expanded && this.accordion.displayMode === 'default';
|
---|
173 | }
|
---|
174 | return false;
|
---|
175 | }
|
---|
176 | /** Gets the expanded state string. */
|
---|
177 | _getExpandedState() {
|
---|
178 | return this.expanded ? 'expanded' : 'collapsed';
|
---|
179 | }
|
---|
180 | /** Toggles the expanded state of the expansion panel. */
|
---|
181 | toggle() {
|
---|
182 | this.expanded = !this.expanded;
|
---|
183 | }
|
---|
184 | /** Sets the expanded state of the expansion panel to false. */
|
---|
185 | close() {
|
---|
186 | this.expanded = false;
|
---|
187 | }
|
---|
188 | /** Sets the expanded state of the expansion panel to true. */
|
---|
189 | open() {
|
---|
190 | this.expanded = true;
|
---|
191 | }
|
---|
192 | ngAfterContentInit() {
|
---|
193 | if (this._lazyContent) {
|
---|
194 | // Render the content as soon as the panel becomes open.
|
---|
195 | this.opened.pipe(startWith(null), filter(() => this.expanded && !this._portal), take(1)).subscribe(() => {
|
---|
196 | this._portal = new TemplatePortal(this._lazyContent._template, this._viewContainerRef);
|
---|
197 | });
|
---|
198 | }
|
---|
199 | }
|
---|
200 | ngOnChanges(changes) {
|
---|
201 | this._inputChanges.next(changes);
|
---|
202 | }
|
---|
203 | ngOnDestroy() {
|
---|
204 | super.ngOnDestroy();
|
---|
205 | this._bodyAnimationDone.complete();
|
---|
206 | this._inputChanges.complete();
|
---|
207 | }
|
---|
208 | /** Checks whether the expansion panel's content contains the currently-focused element. */
|
---|
209 | _containsFocus() {
|
---|
210 | if (this._body) {
|
---|
211 | const focusedElement = this._document.activeElement;
|
---|
212 | const bodyElement = this._body.nativeElement;
|
---|
213 | return focusedElement === bodyElement || bodyElement.contains(focusedElement);
|
---|
214 | }
|
---|
215 | return false;
|
---|
216 | }
|
---|
217 | }
|
---|
218 | MatExpansionPanel.decorators = [
|
---|
219 | { type: Component, args: [{
|
---|
220 | selector: 'mat-expansion-panel',
|
---|
221 | exportAs: 'matExpansionPanel',
|
---|
222 | template: "<ng-content select=\"mat-expansion-panel-header\"></ng-content>\n<div class=\"mat-expansion-panel-content\"\n role=\"region\"\n [@bodyExpansion]=\"_getExpandedState()\"\n (@bodyExpansion.done)=\"_bodyAnimationDone.next($event)\"\n [attr.aria-labelledby]=\"_headerId\"\n [id]=\"id\"\n #body>\n <div class=\"mat-expansion-panel-body\">\n <ng-content></ng-content>\n <ng-template [cdkPortalOutlet]=\"_portal\"></ng-template>\n </div>\n <ng-content select=\"mat-action-row\"></ng-content>\n</div>\n",
|
---|
223 | encapsulation: ViewEncapsulation.None,
|
---|
224 | changeDetection: ChangeDetectionStrategy.OnPush,
|
---|
225 | inputs: ['disabled', 'expanded'],
|
---|
226 | outputs: ['opened', 'closed', 'expandedChange'],
|
---|
227 | animations: [matExpansionAnimations.bodyExpansion],
|
---|
228 | providers: [
|
---|
229 | // Provide MatAccordion as undefined to prevent nested expansion panels from registering
|
---|
230 | // to the same accordion.
|
---|
231 | { provide: MAT_ACCORDION, useValue: ɵ0 },
|
---|
232 | ],
|
---|
233 | host: {
|
---|
234 | 'class': 'mat-expansion-panel',
|
---|
235 | '[class.mat-expanded]': 'expanded',
|
---|
236 | '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
|
---|
237 | '[class.mat-expansion-panel-spacing]': '_hasSpacing()',
|
---|
238 | },
|
---|
239 | styles: [".mat-expansion-panel{box-sizing:content-box;display:block;margin:0;border-radius:4px;overflow:hidden;transition:margin 225ms cubic-bezier(0.4, 0, 0.2, 1),box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);position:relative}.mat-accordion .mat-expansion-panel:not(.mat-expanded),.mat-accordion .mat-expansion-panel:not(.mat-expansion-panel-spacing){border-radius:0}.mat-accordion .mat-expansion-panel:first-of-type{border-top-right-radius:4px;border-top-left-radius:4px}.mat-accordion .mat-expansion-panel:last-of-type{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.cdk-high-contrast-active .mat-expansion-panel{outline:solid 1px}.mat-expansion-panel.ng-animate-disabled,.ng-animate-disabled .mat-expansion-panel,.mat-expansion-panel._mat-animation-noopable{transition:none}.mat-expansion-panel-content{display:flex;flex-direction:column;overflow:visible}.mat-expansion-panel-body{padding:0 24px 16px}.mat-expansion-panel-spacing{margin:16px 0}.mat-accordion>.mat-expansion-panel-spacing:first-child,.mat-accordion>*:first-child:not(.mat-expansion-panel) .mat-expansion-panel-spacing{margin-top:0}.mat-accordion>.mat-expansion-panel-spacing:last-child,.mat-accordion>*:last-child:not(.mat-expansion-panel) .mat-expansion-panel-spacing{margin-bottom:0}.mat-action-row{border-top-style:solid;border-top-width:1px;display:flex;flex-direction:row;justify-content:flex-end;padding:16px 8px 16px 24px}.mat-action-row button.mat-button-base,.mat-action-row button.mat-mdc-button-base{margin-left:8px}[dir=rtl] .mat-action-row button.mat-button-base,[dir=rtl] .mat-action-row button.mat-mdc-button-base{margin-left:0;margin-right:8px}\n"]
|
---|
240 | },] }
|
---|
241 | ];
|
---|
242 | MatExpansionPanel.ctorParameters = () => [
|
---|
243 | { type: undefined, decorators: [{ type: Optional }, { type: SkipSelf }, { type: Inject, args: [MAT_ACCORDION,] }] },
|
---|
244 | { type: ChangeDetectorRef },
|
---|
245 | { type: UniqueSelectionDispatcher },
|
---|
246 | { type: ViewContainerRef },
|
---|
247 | { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
|
---|
248 | { type: String, decorators: [{ type: Optional }, { type: Inject, args: [ANIMATION_MODULE_TYPE,] }] },
|
---|
249 | { type: undefined, decorators: [{ type: Inject, args: [MAT_EXPANSION_PANEL_DEFAULT_OPTIONS,] }, { type: Optional }] }
|
---|
250 | ];
|
---|
251 | MatExpansionPanel.propDecorators = {
|
---|
252 | hideToggle: [{ type: Input }],
|
---|
253 | togglePosition: [{ type: Input }],
|
---|
254 | afterExpand: [{ type: Output }],
|
---|
255 | afterCollapse: [{ type: Output }],
|
---|
256 | _lazyContent: [{ type: ContentChild, args: [MatExpansionPanelContent,] }],
|
---|
257 | _body: [{ type: ViewChild, args: ['body',] }]
|
---|
258 | };
|
---|
259 | /**
|
---|
260 | * Actions of a `<mat-expansion-panel>`.
|
---|
261 | */
|
---|
262 | class MatExpansionPanelActionRow {
|
---|
263 | }
|
---|
264 | MatExpansionPanelActionRow.decorators = [
|
---|
265 | { type: Directive, args: [{
|
---|
266 | selector: 'mat-action-row',
|
---|
267 | host: {
|
---|
268 | class: 'mat-action-row'
|
---|
269 | }
|
---|
270 | },] }
|
---|
271 | ];
|
---|
272 |
|
---|
273 | /**
|
---|
274 | * @license
|
---|
275 | * Copyright Google LLC All Rights Reserved.
|
---|
276 | *
|
---|
277 | * Use of this source code is governed by an MIT-style license that can be
|
---|
278 | * found in the LICENSE file at https://angular.io/license
|
---|
279 | */
|
---|
280 | // Boilerplate for applying mixins to MatExpansionPanelHeader.
|
---|
281 | /** @docs-private */
|
---|
282 | class MatExpansionPanelHeaderBase {
|
---|
283 | }
|
---|
284 | const _MatExpansionPanelHeaderMixinBase = mixinTabIndex(MatExpansionPanelHeaderBase);
|
---|
285 | /**
|
---|
286 | * Header element of a `<mat-expansion-panel>`.
|
---|
287 | */
|
---|
288 | class MatExpansionPanelHeader extends _MatExpansionPanelHeaderMixinBase {
|
---|
289 | constructor(panel, _element, _focusMonitor, _changeDetectorRef, defaultOptions, _animationMode, tabIndex) {
|
---|
290 | super();
|
---|
291 | this.panel = panel;
|
---|
292 | this._element = _element;
|
---|
293 | this._focusMonitor = _focusMonitor;
|
---|
294 | this._changeDetectorRef = _changeDetectorRef;
|
---|
295 | this._animationMode = _animationMode;
|
---|
296 | this._parentChangeSubscription = Subscription.EMPTY;
|
---|
297 | const accordionHideToggleChange = panel.accordion ?
|
---|
298 | panel.accordion._stateChanges.pipe(filter(changes => !!(changes['hideToggle'] || changes['togglePosition']))) :
|
---|
299 | EMPTY;
|
---|
300 | this.tabIndex = parseInt(tabIndex || '') || 0;
|
---|
301 | // Since the toggle state depends on an @Input on the panel, we
|
---|
302 | // need to subscribe and trigger change detection manually.
|
---|
303 | this._parentChangeSubscription =
|
---|
304 | merge(panel.opened, panel.closed, accordionHideToggleChange, panel._inputChanges.pipe(filter(changes => {
|
---|
305 | return !!(changes['hideToggle'] ||
|
---|
306 | changes['disabled'] ||
|
---|
307 | changes['togglePosition']);
|
---|
308 | })))
|
---|
309 | .subscribe(() => this._changeDetectorRef.markForCheck());
|
---|
310 | // Avoids focus being lost if the panel contained the focused element and was closed.
|
---|
311 | panel.closed
|
---|
312 | .pipe(filter(() => panel._containsFocus()))
|
---|
313 | .subscribe(() => _focusMonitor.focusVia(_element, 'program'));
|
---|
314 | if (defaultOptions) {
|
---|
315 | this.expandedHeight = defaultOptions.expandedHeight;
|
---|
316 | this.collapsedHeight = defaultOptions.collapsedHeight;
|
---|
317 | }
|
---|
318 | }
|
---|
319 | /**
|
---|
320 | * Whether the associated panel is disabled. Implemented as a part of `FocusableOption`.
|
---|
321 | * @docs-private
|
---|
322 | */
|
---|
323 | get disabled() {
|
---|
324 | return this.panel.disabled;
|
---|
325 | }
|
---|
326 | /** Toggles the expanded state of the panel. */
|
---|
327 | _toggle() {
|
---|
328 | if (!this.disabled) {
|
---|
329 | this.panel.toggle();
|
---|
330 | }
|
---|
331 | }
|
---|
332 | /** Gets whether the panel is expanded. */
|
---|
333 | _isExpanded() {
|
---|
334 | return this.panel.expanded;
|
---|
335 | }
|
---|
336 | /** Gets the expanded state string of the panel. */
|
---|
337 | _getExpandedState() {
|
---|
338 | return this.panel._getExpandedState();
|
---|
339 | }
|
---|
340 | /** Gets the panel id. */
|
---|
341 | _getPanelId() {
|
---|
342 | return this.panel.id;
|
---|
343 | }
|
---|
344 | /** Gets the toggle position for the header. */
|
---|
345 | _getTogglePosition() {
|
---|
346 | return this.panel.togglePosition;
|
---|
347 | }
|
---|
348 | /** Gets whether the expand indicator should be shown. */
|
---|
349 | _showToggle() {
|
---|
350 | return !this.panel.hideToggle && !this.panel.disabled;
|
---|
351 | }
|
---|
352 | /**
|
---|
353 | * Gets the current height of the header. Null if no custom height has been
|
---|
354 | * specified, and if the default height from the stylesheet should be used.
|
---|
355 | */
|
---|
356 | _getHeaderHeight() {
|
---|
357 | const isExpanded = this._isExpanded();
|
---|
358 | if (isExpanded && this.expandedHeight) {
|
---|
359 | return this.expandedHeight;
|
---|
360 | }
|
---|
361 | else if (!isExpanded && this.collapsedHeight) {
|
---|
362 | return this.collapsedHeight;
|
---|
363 | }
|
---|
364 | return null;
|
---|
365 | }
|
---|
366 | /** Handle keydown event calling to toggle() if appropriate. */
|
---|
367 | _keydown(event) {
|
---|
368 | switch (event.keyCode) {
|
---|
369 | // Toggle for space and enter keys.
|
---|
370 | case SPACE:
|
---|
371 | case ENTER:
|
---|
372 | if (!hasModifierKey(event)) {
|
---|
373 | event.preventDefault();
|
---|
374 | this._toggle();
|
---|
375 | }
|
---|
376 | break;
|
---|
377 | default:
|
---|
378 | if (this.panel.accordion) {
|
---|
379 | this.panel.accordion._handleHeaderKeydown(event);
|
---|
380 | }
|
---|
381 | return;
|
---|
382 | }
|
---|
383 | }
|
---|
384 | /**
|
---|
385 | * Focuses the panel header. Implemented as a part of `FocusableOption`.
|
---|
386 | * @param origin Origin of the action that triggered the focus.
|
---|
387 | * @docs-private
|
---|
388 | */
|
---|
389 | focus(origin, options) {
|
---|
390 | if (origin) {
|
---|
391 | this._focusMonitor.focusVia(this._element, origin, options);
|
---|
392 | }
|
---|
393 | else {
|
---|
394 | this._element.nativeElement.focus(options);
|
---|
395 | }
|
---|
396 | }
|
---|
397 | ngAfterViewInit() {
|
---|
398 | this._focusMonitor.monitor(this._element).subscribe(origin => {
|
---|
399 | if (origin && this.panel.accordion) {
|
---|
400 | this.panel.accordion._handleHeaderFocus(this);
|
---|
401 | }
|
---|
402 | });
|
---|
403 | }
|
---|
404 | ngOnDestroy() {
|
---|
405 | this._parentChangeSubscription.unsubscribe();
|
---|
406 | this._focusMonitor.stopMonitoring(this._element);
|
---|
407 | }
|
---|
408 | }
|
---|
409 | MatExpansionPanelHeader.decorators = [
|
---|
410 | { type: Component, args: [{
|
---|
411 | selector: 'mat-expansion-panel-header',
|
---|
412 | template: "<span class=\"mat-content\">\n <ng-content select=\"mat-panel-title\"></ng-content>\n <ng-content select=\"mat-panel-description\"></ng-content>\n <ng-content></ng-content>\n</span>\n<span [@indicatorRotate]=\"_getExpandedState()\" *ngIf=\"_showToggle()\"\n class=\"mat-expansion-indicator\"></span>\n",
|
---|
413 | encapsulation: ViewEncapsulation.None,
|
---|
414 | changeDetection: ChangeDetectionStrategy.OnPush,
|
---|
415 | inputs: ['tabIndex'],
|
---|
416 | animations: [
|
---|
417 | matExpansionAnimations.indicatorRotate,
|
---|
418 | ],
|
---|
419 | host: {
|
---|
420 | 'class': 'mat-expansion-panel-header mat-focus-indicator',
|
---|
421 | 'role': 'button',
|
---|
422 | '[attr.id]': 'panel._headerId',
|
---|
423 | '[attr.tabindex]': 'tabIndex',
|
---|
424 | '[attr.aria-controls]': '_getPanelId()',
|
---|
425 | '[attr.aria-expanded]': '_isExpanded()',
|
---|
426 | '[attr.aria-disabled]': 'panel.disabled',
|
---|
427 | '[class.mat-expanded]': '_isExpanded()',
|
---|
428 | '[class.mat-expansion-toggle-indicator-after]': `_getTogglePosition() === 'after'`,
|
---|
429 | '[class.mat-expansion-toggle-indicator-before]': `_getTogglePosition() === 'before'`,
|
---|
430 | '[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
|
---|
431 | '[style.height]': '_getHeaderHeight()',
|
---|
432 | '(click)': '_toggle()',
|
---|
433 | '(keydown)': '_keydown($event)',
|
---|
434 | },
|
---|
435 | styles: [".mat-expansion-panel-header{display:flex;flex-direction:row;align-items:center;padding:0 24px;border-radius:inherit;transition:height 225ms cubic-bezier(0.4, 0, 0.2, 1)}.mat-expansion-panel-header._mat-animation-noopable{transition:none}.mat-expansion-panel-header:focus,.mat-expansion-panel-header:hover{outline:none}.mat-expansion-panel-header.mat-expanded:focus,.mat-expansion-panel-header.mat-expanded:hover{background:inherit}.mat-expansion-panel-header:not([aria-disabled=true]){cursor:pointer}.mat-expansion-panel-header.mat-expansion-toggle-indicator-before{flex-direction:row-reverse}.mat-expansion-panel-header.mat-expansion-toggle-indicator-before .mat-expansion-indicator{margin:0 16px 0 0}[dir=rtl] .mat-expansion-panel-header.mat-expansion-toggle-indicator-before .mat-expansion-indicator{margin:0 0 0 16px}.mat-content{display:flex;flex:1;flex-direction:row;overflow:hidden}.mat-expansion-panel-header-title,.mat-expansion-panel-header-description{display:flex;flex-grow:1;margin-right:16px}[dir=rtl] .mat-expansion-panel-header-title,[dir=rtl] .mat-expansion-panel-header-description{margin-right:0;margin-left:16px}.mat-expansion-panel-header-description{flex-grow:2}.mat-expansion-indicator::after{border-style:solid;border-width:0 2px 2px 0;content:\"\";display:inline-block;padding:3px;transform:rotate(45deg);vertical-align:middle}.cdk-high-contrast-active .mat-expansion-panel .mat-expansion-panel-header.cdk-keyboard-focused:not([aria-disabled=true])::before,.cdk-high-contrast-active .mat-expansion-panel .mat-expansion-panel-header.cdk-program-focused:not([aria-disabled=true])::before,.cdk-high-contrast-active .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:hover:not([aria-disabled=true])::before{top:0;left:0;right:0;bottom:0;position:absolute;box-sizing:border-box;pointer-events:none;border:3px solid;border-radius:4px;content:\"\"}.cdk-high-contrast-active .mat-expansion-panel-content{border-top:1px solid;border-top-left-radius:0;border-top-right-radius:0}\n"]
|
---|
436 | },] }
|
---|
437 | ];
|
---|
438 | MatExpansionPanelHeader.ctorParameters = () => [
|
---|
439 | { type: MatExpansionPanel, decorators: [{ type: Host }] },
|
---|
440 | { type: ElementRef },
|
---|
441 | { type: FocusMonitor },
|
---|
442 | { type: ChangeDetectorRef },
|
---|
443 | { type: undefined, decorators: [{ type: Inject, args: [MAT_EXPANSION_PANEL_DEFAULT_OPTIONS,] }, { type: Optional }] },
|
---|
444 | { type: String, decorators: [{ type: Optional }, { type: Inject, args: [ANIMATION_MODULE_TYPE,] }] },
|
---|
445 | { type: String, decorators: [{ type: Attribute, args: ['tabindex',] }] }
|
---|
446 | ];
|
---|
447 | MatExpansionPanelHeader.propDecorators = {
|
---|
448 | expandedHeight: [{ type: Input }],
|
---|
449 | collapsedHeight: [{ type: Input }]
|
---|
450 | };
|
---|
451 | /**
|
---|
452 | * Description element of a `<mat-expansion-panel-header>`.
|
---|
453 | */
|
---|
454 | class MatExpansionPanelDescription {
|
---|
455 | }
|
---|
456 | MatExpansionPanelDescription.decorators = [
|
---|
457 | { type: Directive, args: [{
|
---|
458 | selector: 'mat-panel-description',
|
---|
459 | host: {
|
---|
460 | class: 'mat-expansion-panel-header-description'
|
---|
461 | }
|
---|
462 | },] }
|
---|
463 | ];
|
---|
464 | /**
|
---|
465 | * Title element of a `<mat-expansion-panel-header>`.
|
---|
466 | */
|
---|
467 | class MatExpansionPanelTitle {
|
---|
468 | }
|
---|
469 | MatExpansionPanelTitle.decorators = [
|
---|
470 | { type: Directive, args: [{
|
---|
471 | selector: 'mat-panel-title',
|
---|
472 | host: {
|
---|
473 | class: 'mat-expansion-panel-header-title'
|
---|
474 | }
|
---|
475 | },] }
|
---|
476 | ];
|
---|
477 |
|
---|
478 | /**
|
---|
479 | * @license
|
---|
480 | * Copyright Google LLC All Rights Reserved.
|
---|
481 | *
|
---|
482 | * Use of this source code is governed by an MIT-style license that can be
|
---|
483 | * found in the LICENSE file at https://angular.io/license
|
---|
484 | */
|
---|
485 | /**
|
---|
486 | * Directive for a Material Design Accordion.
|
---|
487 | */
|
---|
488 | class MatAccordion extends CdkAccordion {
|
---|
489 | constructor() {
|
---|
490 | super(...arguments);
|
---|
491 | /** Headers belonging to this accordion. */
|
---|
492 | this._ownHeaders = new QueryList();
|
---|
493 | this._hideToggle = false;
|
---|
494 | /**
|
---|
495 | * Display mode used for all expansion panels in the accordion. Currently two display
|
---|
496 | * modes exist:
|
---|
497 | * default - a gutter-like spacing is placed around any expanded panel, placing the expanded
|
---|
498 | * panel at a different elevation from the rest of the accordion.
|
---|
499 | * flat - no spacing is placed around expanded panels, showing all panels at the same
|
---|
500 | * elevation.
|
---|
501 | */
|
---|
502 | this.displayMode = 'default';
|
---|
503 | /** The position of the expansion indicator. */
|
---|
504 | this.togglePosition = 'after';
|
---|
505 | }
|
---|
506 | /** Whether the expansion indicator should be hidden. */
|
---|
507 | get hideToggle() { return this._hideToggle; }
|
---|
508 | set hideToggle(show) { this._hideToggle = coerceBooleanProperty(show); }
|
---|
509 | ngAfterContentInit() {
|
---|
510 | this._headers.changes
|
---|
511 | .pipe(startWith(this._headers))
|
---|
512 | .subscribe((headers) => {
|
---|
513 | this._ownHeaders.reset(headers.filter(header => header.panel.accordion === this));
|
---|
514 | this._ownHeaders.notifyOnChanges();
|
---|
515 | });
|
---|
516 | this._keyManager = new FocusKeyManager(this._ownHeaders).withWrap().withHomeAndEnd();
|
---|
517 | }
|
---|
518 | /** Handles keyboard events coming in from the panel headers. */
|
---|
519 | _handleHeaderKeydown(event) {
|
---|
520 | this._keyManager.onKeydown(event);
|
---|
521 | }
|
---|
522 | _handleHeaderFocus(header) {
|
---|
523 | this._keyManager.updateActiveItem(header);
|
---|
524 | }
|
---|
525 | ngOnDestroy() {
|
---|
526 | super.ngOnDestroy();
|
---|
527 | this._ownHeaders.destroy();
|
---|
528 | }
|
---|
529 | }
|
---|
530 | MatAccordion.decorators = [
|
---|
531 | { type: Directive, args: [{
|
---|
532 | selector: 'mat-accordion',
|
---|
533 | exportAs: 'matAccordion',
|
---|
534 | inputs: ['multi'],
|
---|
535 | providers: [{
|
---|
536 | provide: MAT_ACCORDION,
|
---|
537 | useExisting: MatAccordion
|
---|
538 | }],
|
---|
539 | host: {
|
---|
540 | class: 'mat-accordion',
|
---|
541 | // Class binding which is only used by the test harness as there is no other
|
---|
542 | // way for the harness to detect if multiple panel support is enabled.
|
---|
543 | '[class.mat-accordion-multi]': 'this.multi',
|
---|
544 | }
|
---|
545 | },] }
|
---|
546 | ];
|
---|
547 | MatAccordion.propDecorators = {
|
---|
548 | _headers: [{ type: ContentChildren, args: [MatExpansionPanelHeader, { descendants: true },] }],
|
---|
549 | hideToggle: [{ type: Input }],
|
---|
550 | displayMode: [{ type: Input }],
|
---|
551 | togglePosition: [{ type: Input }]
|
---|
552 | };
|
---|
553 |
|
---|
554 | /**
|
---|
555 | * @license
|
---|
556 | * Copyright Google LLC All Rights Reserved.
|
---|
557 | *
|
---|
558 | * Use of this source code is governed by an MIT-style license that can be
|
---|
559 | * found in the LICENSE file at https://angular.io/license
|
---|
560 | */
|
---|
561 | class MatExpansionModule {
|
---|
562 | }
|
---|
563 | MatExpansionModule.decorators = [
|
---|
564 | { type: NgModule, args: [{
|
---|
565 | imports: [CommonModule, MatCommonModule, CdkAccordionModule, PortalModule],
|
---|
566 | exports: [
|
---|
567 | MatAccordion,
|
---|
568 | MatExpansionPanel,
|
---|
569 | MatExpansionPanelActionRow,
|
---|
570 | MatExpansionPanelHeader,
|
---|
571 | MatExpansionPanelTitle,
|
---|
572 | MatExpansionPanelDescription,
|
---|
573 | MatExpansionPanelContent,
|
---|
574 | ],
|
---|
575 | declarations: [
|
---|
576 | MatAccordion,
|
---|
577 | MatExpansionPanel,
|
---|
578 | MatExpansionPanelActionRow,
|
---|
579 | MatExpansionPanelHeader,
|
---|
580 | MatExpansionPanelTitle,
|
---|
581 | MatExpansionPanelDescription,
|
---|
582 | MatExpansionPanelContent,
|
---|
583 | ],
|
---|
584 | },] }
|
---|
585 | ];
|
---|
586 |
|
---|
587 | /**
|
---|
588 | * @license
|
---|
589 | * Copyright Google LLC All Rights Reserved.
|
---|
590 | *
|
---|
591 | * Use of this source code is governed by an MIT-style license that can be
|
---|
592 | * found in the LICENSE file at https://angular.io/license
|
---|
593 | */
|
---|
594 |
|
---|
595 | /**
|
---|
596 | * Generated bundle index. Do not edit.
|
---|
597 | */
|
---|
598 |
|
---|
599 | export { EXPANSION_PANEL_ANIMATION_TIMING, MAT_ACCORDION, MAT_EXPANSION_PANEL_DEFAULT_OPTIONS, MatAccordion, MatExpansionModule, MatExpansionPanel, MatExpansionPanelActionRow, MatExpansionPanelContent, MatExpansionPanelDescription, MatExpansionPanelHeader, MatExpansionPanelTitle, matExpansionAnimations, ɵ0 };
|
---|
600 | //# sourceMappingURL=expansion.js.map
|
---|