Skip to content

Commit 3de3851

Browse files
crisbetovivian-hu-zz
authored andcommitted
feat(bottom-sheet): add injection token for default options (#13172)
Introduces the `MAT_BOTTOM_SHEET_DEFAULT_OPTIONS` token which can be used to set the default options for `MatBottomSheet`. Fixes #13149.
1 parent ab44d50 commit 3de3851

File tree

3 files changed

+113
-6
lines changed

3 files changed

+113
-6
lines changed

src/lib/bottom-sheet/bottom-sheet.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ inside your `NgModule`.
8181
export class AppModule {}
8282
```
8383

84+
### Specifying global configuration defaults
85+
Default bottom sheet options can be specified by providing an instance of `MatBottomSheetConfig`
86+
for `MAT_BOTTOM_SHEET_DEFAULT_OPTIONS` in your application's root module.
87+
88+
```ts
89+
@NgModule({
90+
providers: [
91+
{provide: MAT_BOTTOM_SHEET_DEFAULT_OPTIONS, useValue: {hasBackdrop: false}}
92+
]
93+
})
94+
```
95+
96+
8497
### Accessibility
8598
By default, the bottom sheet has `role="dialog"` on the root element and can be labelled using the
8699
`ariaLabel` property on the `MatBottomSheetConfig`.

src/lib/bottom-sheet/bottom-sheet.spec.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import {Location} from '@angular/common';
2626
import {SpyLocation} from '@angular/common/testing';
2727
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
28-
import {MatBottomSheet} from './bottom-sheet';
28+
import {MatBottomSheet, MAT_BOTTOM_SHEET_DEFAULT_OPTIONS} from './bottom-sheet';
2929
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetConfig} from './bottom-sheet-config';
3030
import {MatBottomSheetModule} from './bottom-sheet-module';
3131
import {MatBottomSheetRef} from './bottom-sheet-ref';
@@ -616,6 +616,82 @@ describe('MatBottomSheet with parent MatBottomSheet', () => {
616616
}));
617617
});
618618

619+
describe('MatBottomSheet with default options', () => {
620+
let bottomSheet: MatBottomSheet;
621+
let overlayContainer: OverlayContainer;
622+
let overlayContainerElement: HTMLElement;
623+
624+
let testViewContainerRef: ViewContainerRef;
625+
let viewContainerFixture: ComponentFixture<ComponentWithChildViewContainer>;
626+
627+
beforeEach(fakeAsync(() => {
628+
const defaultConfig: MatBottomSheetConfig = {
629+
hasBackdrop: false,
630+
disableClose: true,
631+
autoFocus: false
632+
};
633+
634+
TestBed.configureTestingModule({
635+
imports: [MatBottomSheetModule, BottomSheetTestModule],
636+
providers: [
637+
{provide: MAT_BOTTOM_SHEET_DEFAULT_OPTIONS, useValue: defaultConfig},
638+
],
639+
});
640+
641+
TestBed.compileComponents();
642+
}));
643+
644+
beforeEach(inject([MatBottomSheet, OverlayContainer],
645+
(b: MatBottomSheet, oc: OverlayContainer) => {
646+
bottomSheet = b;
647+
overlayContainer = oc;
648+
overlayContainerElement = oc.getContainerElement();
649+
}));
650+
651+
afterEach(() => {
652+
overlayContainer.ngOnDestroy();
653+
});
654+
655+
beforeEach(() => {
656+
viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer);
657+
658+
viewContainerFixture.detectChanges();
659+
testViewContainerRef = viewContainerFixture.componentInstance.childViewContainer;
660+
});
661+
662+
it('should use the provided defaults', () => {
663+
bottomSheet.open(PizzaMsg, {viewContainerRef: testViewContainerRef});
664+
665+
viewContainerFixture.detectChanges();
666+
667+
expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeFalsy();
668+
669+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
670+
671+
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeTruthy();
672+
expect(document.activeElement.tagName).not.toBe('INPUT');
673+
});
674+
675+
it('should be overridable by open() options', fakeAsync(() => {
676+
bottomSheet.open(PizzaMsg, {
677+
hasBackdrop: true,
678+
disableClose: false,
679+
viewContainerRef: testViewContainerRef
680+
});
681+
682+
viewContainerFixture.detectChanges();
683+
684+
expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeTruthy();
685+
686+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);
687+
viewContainerFixture.detectChanges();
688+
flush();
689+
690+
expect(overlayContainerElement.querySelector('mat-bottom-sheet-container')).toBeFalsy();
691+
}));
692+
});
693+
694+
619695

620696
@Directive({selector: 'dir-with-view-container'})
621697
class DirectiveWithViewContainer {

src/lib/bottom-sheet/bottom-sheet.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,16 @@
99
import {Directionality} from '@angular/cdk/bidi';
1010
import {Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay';
1111
import {ComponentPortal, ComponentType, PortalInjector, TemplatePortal} from '@angular/cdk/portal';
12-
import {ComponentRef, Injectable, Injector, Optional, SkipSelf, TemplateRef} from '@angular/core';
12+
import {
13+
ComponentRef,
14+
Injectable,
15+
Injector,
16+
Optional,
17+
SkipSelf,
18+
TemplateRef,
19+
InjectionToken,
20+
Inject,
21+
} from '@angular/core';
1322
import {Location} from '@angular/common';
1423
import {of as observableOf} from 'rxjs';
1524
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetConfig} from './bottom-sheet-config';
@@ -18,6 +27,10 @@ import {MatBottomSheetModule} from './bottom-sheet-module';
1827
import {MatBottomSheetRef} from './bottom-sheet-ref';
1928

2029

30+
/** Injection token that can be used to specify default bottom sheet options. */
31+
export const MAT_BOTTOM_SHEET_DEFAULT_OPTIONS =
32+
new InjectionToken<MatBottomSheetConfig>('mat-bottom-sheet-default-options');
33+
2134
/**
2235
* Service to trigger Material Design bottom sheets.
2336
*/
@@ -43,7 +56,9 @@ export class MatBottomSheet {
4356
private _overlay: Overlay,
4457
private _injector: Injector,
4558
@Optional() @SkipSelf() private _parentBottomSheet: MatBottomSheet,
46-
@Optional() private _location?: Location) {}
59+
@Optional() private _location?: Location,
60+
@Optional() @Inject(MAT_BOTTOM_SHEET_DEFAULT_OPTIONS)
61+
private _defaultOptions?: MatBottomSheetConfig) {}
4762

4863
open<T, D = any, R = any>(component: ComponentType<T>,
4964
config?: MatBottomSheetConfig<D>): MatBottomSheetRef<T, R>;
@@ -53,7 +68,8 @@ export class MatBottomSheet {
5368
open<T, D = any, R = any>(componentOrTemplateRef: ComponentType<T> | TemplateRef<T>,
5469
config?: MatBottomSheetConfig<D>): MatBottomSheetRef<T, R> {
5570

56-
const _config = _applyConfigDefaults(config);
71+
const _config =
72+
_applyConfigDefaults(this._defaultOptions || new MatBottomSheetConfig(), config);
5773
const overlayRef = this._createOverlay(_config);
5874
const container = this._attachContainer(overlayRef, _config);
5975
const ref = new MatBottomSheetRef<T, R>(container, overlayRef, this._location);
@@ -171,9 +187,11 @@ export class MatBottomSheet {
171187

172188
/**
173189
* Applies default options to the bottom sheet config.
190+
* @param defaults Object containing the default values to which to fall back.
174191
* @param config The configuration to which the defaults will be applied.
175192
* @returns The new configuration object with defaults applied.
176193
*/
177-
function _applyConfigDefaults(config?: MatBottomSheetConfig): MatBottomSheetConfig {
178-
return {...new MatBottomSheetConfig(), ...config};
194+
function _applyConfigDefaults(defaults: MatBottomSheetConfig,
195+
config?: MatBottomSheetConfig): MatBottomSheetConfig {
196+
return {...defaults, ...config};
179197
}

0 commit comments

Comments
 (0)