Skip to content

Commit

Permalink
feat: add bottom sheet component
Browse files Browse the repository at this point in the history
* Adds an initial implementation of the new `MatBottomSheet` service that allows users to display component-based or template-based bottom sheets.
* Sets up the various boilerplate and infrastructure necessary for a new component.

Note: this is an initial implementation that has the necessary functionality, styles and accessibility. More docs, examples and touch gestures will be added in a follow-up.
  • Loading branch information
crisbeto committed Feb 2, 2018
1 parent e30852a commit 83f03f0
Show file tree
Hide file tree
Showing 29 changed files with 1,429 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Angular Material components
/src/lib/* @jelbourn
/src/lib/autocomplete/** @kara @crisbeto
/src/lib/bottom-sheet/** @jelbourn @crisbeto
/src/lib/button-toggle/** @tinayuangao
/src/lib/button/** @tinayuangao
/src/lib/card/** @jelbourn
Expand Down
45 changes: 45 additions & 0 deletions src/demo-app/bottom-sheet/bottom-sheet-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<h1>Bottom sheet demo</h1>

<button mat-raised-button color="primary" (click)="openComponent()">Open component sheet</button>
<button mat-raised-button color="accent" (click)="openTemplate()">Open template sheet</button>

<mat-card class="demo-dialog-card">
<mat-card-content>
<h2>Options</h2>

<p>
<mat-checkbox [(ngModel)]="config.hasBackdrop">Has backdrop</mat-checkbox>
</p>

<p>
<mat-checkbox [(ngModel)]="config.disableClose">Disable close</mat-checkbox>
</p>

<p>
<mat-form-field>
<input matInput [(ngModel)]="config.backdropClass" placeholder="Backdrop class">
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-select placeholder="Direction" [(ngModel)]="config.direction">
<mat-option value="ltr">LTR</mat-option>
<mat-option value="rtl">RTL</mat-option>
</mat-select>
</mat-form-field>
</p>

</mat-card-content>
</mat-card>


<ng-template let-bottomSheetRef="bottomSheetRef">
<mat-nav-list>
<mat-list-item (click)="bottomSheetRef.dismiss()" *ngFor="let action of [1, 2, 3]">
<mat-icon mat-list-icon>folder</mat-icon>
<span mat-line>Action {{ link }}</span>
<span mat-line>Description</span>
</mat-list-item>
</mat-nav-list>
</ng-template>
8 changes: 8 additions & 0 deletions src/demo-app/bottom-sheet/bottom-sheet-demo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.demo-dialog-card {
max-width: 405px;
margin: 20px 0;
}

.mat-raised-button {
margin-right: 5px;
}
66 changes: 66 additions & 0 deletions src/demo-app/bottom-sheet/bottom-sheet-demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {Component, ViewEncapsulation, TemplateRef, ViewChild} from '@angular/core';
import {
MatBottomSheet,
MatBottomSheetRef,
MatBottomSheetConfig,
} from '@angular/material/bottom-sheet';

const defaultConfig = new MatBottomSheetConfig();

@Component({
moduleId: module.id,
selector: 'bottom-sheet-demo',
styleUrls: ['bottom-sheet-demo.css'],
templateUrl: 'bottom-sheet-demo.html',
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
})
export class BottomSheetDemo {
config: MatBottomSheetConfig = {
hasBackdrop: defaultConfig.hasBackdrop,
disableClose: defaultConfig.disableClose,
backdropClass: defaultConfig.backdropClass,
direction: 'ltr'
};

@ViewChild(TemplateRef) template: TemplateRef<any>;

constructor(private _bottomSheet: MatBottomSheet) {}

openComponent() {
this._bottomSheet.open(ExampleBottomSheet, this.config);
}

openTemplate() {
this._bottomSheet.open(this.template, this.config);
}
}


@Component({
template: `
<mat-nav-list>
<a href="#" mat-list-item (click)="handleClick($event)" *ngFor="let action of [1, 2, 3]">
<mat-icon mat-list-icon>folder</mat-icon>
<span mat-line>Action {{ link }}</span>
<span mat-line>Description</span>
</a>
</mat-nav-list>
`
})
export class ExampleBottomSheet {
constructor(private sheet: MatBottomSheetRef) {}

handleClick(event: MouseEvent) {
event.preventDefault();
this.sheet.dismiss();
}
}
1 change: 1 addition & 0 deletions src/demo-app/demo-app/demo-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class DemoApp {
dark = false;
navItems = [
{name: 'Autocomplete', route: '/autocomplete'},
{name: 'Bottom sheet', route: '/bottom-sheet'},
{name: 'Button Toggle', route: '/button-toggle'},
{name: 'Button', route: '/button'},
{name: 'Card', route: '/card'},
Expand Down
4 changes: 4 additions & 0 deletions src/demo-app/demo-app/demo-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {AutocompleteDemo} from '../autocomplete/autocomplete-demo';
import {BottomSheetDemo, ExampleBottomSheet} from '../bottom-sheet/bottom-sheet-demo';
import {BaselineDemo} from '../baseline/baseline-demo';
import {ButtonToggleDemo} from '../button-toggle/button-toggle-demo';
import {ButtonDemo} from '../button/button-demo';
Expand Down Expand Up @@ -71,6 +72,7 @@ import {TableDemoModule} from '../table/table-demo-module';
],
declarations: [
AutocompleteDemo,
BottomSheetDemo,
BaselineDemo,
ButtonDemo,
ButtonToggleDemo,
Expand Down Expand Up @@ -120,6 +122,7 @@ import {TableDemoModule} from '../table/table-demo-module';
ToolbarDemo,
TooltipDemo,
TypographyDemo,
ExampleBottomSheet,
],
providers: [
{provide: OverlayContainer, useClass: FullscreenOverlayContainer},
Expand All @@ -133,6 +136,7 @@ import {TableDemoModule} from '../table/table-demo-module';
RotiniPanel,
ScienceJoke,
SpagettiPanel,
ExampleBottomSheet,
],
})
export class DemoModule {}
2 changes: 2 additions & 0 deletions src/demo-app/demo-app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Routes} from '@angular/router';
import {AccessibilityDemo} from '../a11y/a11y';
import {ACCESSIBILITY_DEMO_ROUTES} from '../a11y/routes';
import {AutocompleteDemo} from '../autocomplete/autocomplete-demo';
import {BottomSheetDemo} from '../bottom-sheet/bottom-sheet-demo';
import {BaselineDemo} from '../baseline/baseline-demo';
import {ButtonToggleDemo} from '../button-toggle/button-toggle-demo';
import {ButtonDemo} from '../button/button-demo';
Expand Down Expand Up @@ -55,6 +56,7 @@ export const DEMO_APP_ROUTES: Routes = [
{path: '', component: DemoApp, children: [
{path: '', component: Home},
{path: 'autocomplete', component: AutocompleteDemo},
{path: 'bottom-sheet', component: BottomSheetDemo},
{path: 'baseline', component: BaselineDemo},
{path: 'button', component: ButtonDemo},
{path: 'button-toggle', component: ButtonToggleDemo},
Expand Down
2 changes: 2 additions & 0 deletions src/demo-app/demo-material-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import {NgModule} from '@angular/core';
import {
MatAutocompleteModule,
MatBottomSheetModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
Expand Down Expand Up @@ -56,6 +57,7 @@ import {PortalModule} from '@angular/cdk/portal';
@NgModule({
exports: [
MatAutocompleteModule,
MatBottomSheetModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
Expand Down
1 change: 1 addition & 0 deletions src/demo-app/system-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ System.config({
'@angular/cdk/table': 'dist/packages/cdk/table/index.js',

'@angular/material/autocomplete': 'dist/packages/material/autocomplete/index.js',
'@angular/material/bottom-sheet': 'dist/packages/material/bottom-sheet/index.js',
'@angular/material/button': 'dist/packages/material/button/index.js',
'@angular/material/button-toggle': 'dist/packages/material/button-toggle/index.js',
'@angular/material/card': 'dist/packages/material/card/index.js',
Expand Down
1 change: 1 addition & 0 deletions src/e2e-app/system-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ System.config({
'@angular/material-examples': 'dist/bundles/material-examples.umd.js',

'@angular/material/autocomplete': 'dist/bundles/material-autocomplete.umd.js',
'@angular/material/bottom-sheet': 'dist/bundles/material-bottom-sheet.umd.js',
'@angular/material/button': 'dist/bundles/material-button.umd.js',
'@angular/material/button-toggle': 'dist/bundles/material-button-toggle.umd.js',
'@angular/material/card': 'dist/bundles/material-card.umd.js',
Expand Down
38 changes: 38 additions & 0 deletions src/lib/bottom-sheet/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package(default_visibility=["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@io_bazel_rules_sass//sass:sass.bzl", "sass_library", "sass_binary")


ng_module(
name = "bottom-sheet",
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts"]),
module_name = "@angular/material/bottom_sheet",
assets = [
":bottom_sheet_container_css",
],
deps = [
"//src/lib/core",
"//src/cdk/a11y",
"//src/cdk/overlay",
"//src/cdk/portal",
"//src/cdk/layout",
"@rxjs",
],
tsconfig = ":tsconfig-build.json",
)


sass_binary(
name = "bottom_sheet_container_scss",
src = "bottom-sheet-container.scss",
deps = ["//src/lib/core:core_scss_lib"],
)

# TODO(jelbourn): remove this when sass_binary supports specifying an output filename and dir.
# Copy the output of the sass_binary such that the filename and path match what we expect.
genrule(
name = "bottom_sheet_container_css",
srcs = [":bottom_sheet_container_scss"],
outs = ["bottom-sheet-container.css"],
cmd = "cat $(locations :bottom_sheet_container_scss) > $@",
)
1 change: 1 addition & 0 deletions src/lib/bottom-sheet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Please see the official documentation at https://material.angular.io/components/component/bottom-sheet
21 changes: 21 additions & 0 deletions src/lib/bottom-sheet/_bottom-sheet-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@import '../core/typography/typography-utils';
@import '../core/theming/palette';

@mixin mat-bottom-sheet-theme($theme) {
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);

.mat-bottom-sheet-container {
background: mat-color($background, dialog);
color: mat-color($foreground, text);
}
}

@mixin mat-bottom-sheet-typography($config) {
.mat-bottom-sheet-container {
// Note: we don't use the line-height, because it's way too big.
font-family: mat-font-family($config);
font-size: mat-font-size($config, subheading-2);
font-weight: mat-font-weight($config, subheading-2);
}
}
31 changes: 31 additions & 0 deletions src/lib/bottom-sheet/bottom-sheet-animations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
animate,
state,
style,
transition,
trigger,
AnimationTriggerMetadata,
} from '@angular/animations';
import {AnimationCurves, AnimationDurations} from '@angular/material/core';

/** Animations used by the Material bottom sheet. */
export const matBottomSheetAnimations: {
readonly bottomSheetState: AnimationTriggerMetadata;
} = {
/** Animation that shows and hides a bottom sheet. */
bottomSheetState: trigger('state', [
state('void, hidden', style({transform: 'translateY(100%)'})),
state('visible', style({transform: 'translateY(0%)'})),
transition('visible => void, visible => hidden',
animate(`${AnimationDurations.COMPLEX} ${AnimationCurves.ACCELERATION_CURVE}`)),
transition('void => visible',
animate(`${AnimationDurations.EXITING} ${AnimationCurves.DECELERATION_CURVE}`)),
])
};
42 changes: 42 additions & 0 deletions src/lib/bottom-sheet/bottom-sheet-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {ViewContainerRef, InjectionToken} from '@angular/core';
import {Direction} from '@angular/cdk/bidi';

/** Injection token that can be used to access the data that was passed in to a bottom sheet. */
export const MAT_BOTTOM_SHEET_DATA = new InjectionToken<any>('MatBottomSheetData');

/**
* Configuration used when opening a bottom sheet.
*/
export class MatBottomSheetConfig<D = any> {
/** The view container to place the overlay for the bottom sheet into. */
viewContainerRef?: ViewContainerRef;

/** Extra CSS classes to be added to the bottom sheet container. */
panelClass?: string | string[];

/** Text layout direction for the bottom sheet. */
direction?: Direction = 'ltr';

/** Data being injected into the child component. */
data?: D | null = null;

/** Whether the bottom sheet has a backdrop. */
hasBackdrop?: boolean = true;

/** Custom class for the backdrop. */
backdropClass?: string;

/** Whether the user can use escape or clicking outside to close the bottom sheet. */
disableClose?: boolean = false;

/** Aria label to assign to the bottom sheet element. */
ariaLabel?: string | null = null;
}
1 change: 1 addition & 0 deletions src/lib/bottom-sheet/bottom-sheet-container.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ng-template cdkPortalOutlet></ng-template>
31 changes: 31 additions & 0 deletions src/lib/bottom-sheet/bottom-sheet-container.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@import '../core/style/elevation';

// The bottom sheet minimum width on larger screen sizes is based
// on increments of the toolbar, according to the spec. See:
// https://material.io/guidelines/components/bottom-sheets.html#bottom-sheets-specs
$_mat-bottom-sheet-width-increment: 64px;
$mat-bottom-sheet-container-vertical-padding: 8px !default;
$mat-bottom-sheet-container-horizontal-padding: 16px !default;

.mat-bottom-sheet-container {
@include mat-elevation(16);

padding: $mat-bottom-sheet-container-vertical-padding
$mat-bottom-sheet-container-horizontal-padding;
min-width: 100vw;
box-sizing: border-box;
display: block;
outline: 0;
}

.mat-bottom-sheet-container-medium {
min-width: $_mat-bottom-sheet-width-increment * 6;
}

.mat-bottom-sheet-container-large {
min-width: $_mat-bottom-sheet-width-increment * 8;
}

.mat-bottom-sheet-container-xlarge {
min-width: $_mat-bottom-sheet-width-increment * 9;
}
Loading

0 comments on commit 83f03f0

Please sign in to comment.