diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c7605874fa22..5285df2f5a4a 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -109,6 +109,8 @@
/src/demo-app/demo-app/** @jelbourn
/src/demo-app/dialog/** @jelbourn @crisbeto
/src/demo-app/drawer/** @mmalerba
+/src/demo-app/example/** @andrewseguin
+/src/demo-app/examples-page/** @andrewseguin
/src/demo-app/expansion/** @josephperrott
/src/demo-app/focus-origin/** @mmalerba
/src/demo-app/gestures/** @jelbourn
diff --git a/package.json b/package.json
index 4171701b525c..a100196db024 100644
--- a/package.json
+++ b/package.json
@@ -30,8 +30,10 @@
"@angular/common": "6.0.0-rc.6",
"@angular/compiler": "6.0.0-rc.6",
"@angular/core": "6.0.0-rc.6",
+ "@angular/elements": "6.0.0-rc.6",
"@angular/forms": "6.0.0-rc.6",
"@angular/platform-browser": "6.0.0-rc.6",
+ "@webcomponents/custom-elements": "^1.1.0",
"core-js": "^2.4.1",
"rxjs": "6.0.0",
"systemjs": "0.19.43",
diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts
index 7de17139b64f..10b18e36c496 100644
--- a/src/demo-app/demo-app/demo-app.ts
+++ b/src/demo-app/demo-app/demo-app.ts
@@ -48,6 +48,7 @@ export class Home {}
export class DemoApp {
dark = false;
navItems = [
+ {name: 'Examples', route: '/examples'},
{name: 'Autocomplete', route: '/autocomplete'},
{name: 'Badge', route: '/badge'},
{name: 'Bottom sheet', route: '/bottom-sheet'},
diff --git a/src/demo-app/demo-app/demo-module.ts b/src/demo-app/demo-app/demo-module.ts
index 6316c3134a12..b44018c93f2d 100644
--- a/src/demo-app/demo-app/demo-module.ts
+++ b/src/demo-app/demo-app/demo-module.ts
@@ -9,9 +9,12 @@
import {LayoutModule} from '@angular/cdk/layout';
import {FullscreenOverlayContainer, OverlayContainer} from '@angular/cdk/overlay';
import {CommonModule} from '@angular/common';
-import {NgModule} from '@angular/core';
+import {Injector, NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
+import {createCustomElement} from '@angular/elements';
+import {EXAMPLE_COMPONENTS, ExampleModule} from '@angular/material-examples';
+
import {AutocompleteDemo} from '../autocomplete/autocomplete-demo';
import {BadgeDemo} from '../badge/badge-demo';
import {BaselineDemo} from '../baseline/baseline-demo';
@@ -65,9 +68,13 @@ import {TypographyDemo} from '../typography/typography-demo';
import {DemoApp, Home} from './demo-app';
import {DEMO_APP_ROUTES} from './routes';
import {PaginatorDemo} from '../paginator/paginator-demo';
+import {ExamplesPage} from '../examples-page/examples-page';
+import {MaterialExampleModule} from '../example/example-module';
@NgModule({
imports: [
+ MaterialExampleModule,
+ ExampleModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
@@ -78,6 +85,7 @@ import {PaginatorDemo} from '../paginator/paginator-demo';
TreeDemoModule,
],
declarations: [
+ ExamplesPage,
AutocompleteDemo,
BadgeDemo,
BaselineDemo,
@@ -155,4 +163,12 @@ import {PaginatorDemo} from '../paginator/paginator-demo';
SpaghettiPanel,
],
})
-export class DemoModule {}
+export class DemoModule {
+ constructor(injector: Injector) {
+ // Register examples as custom elements so that they can be inserted into the DOM dynamically
+ Object.keys(EXAMPLE_COMPONENTS).forEach(key => {
+ const element = createCustomElement(EXAMPLE_COMPONENTS[key].component, {injector});
+ customElements.define(key, element);
+ });
+ }
+}
diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts
index fe9f4bc8fad0..15d9e8e218a9 100644
--- a/src/demo-app/demo-app/routes.ts
+++ b/src/demo-app/demo-app/routes.ts
@@ -56,6 +56,7 @@ import {BadgeDemo} from '../badge/badge-demo';
import {ConnectedOverlayDemo} from '../connected-overlay/connected-overlay-demo';
import {PaginatorDemo} from '../paginator/paginator-demo';
+import {ExamplesPage} from '../examples-page/examples-page';
export const DEMO_APP_ROUTES: Routes = [
{path: '', component: DemoApp, children: [
@@ -105,6 +106,7 @@ export const DEMO_APP_ROUTES: Routes = [
{path: 'stepper', component: StepperDemo},
{path: 'screen-type', component: ScreenTypeDemo},
{path: 'connected-overlay', component: ConnectedOverlayDemo},
+ {path: 'examples', component: ExamplesPage}
]}
];
diff --git a/src/demo-app/example/example-list.ts b/src/demo-app/example/example-list.ts
new file mode 100644
index 000000000000..d7b617fd01c3
--- /dev/null
+++ b/src/demo-app/example/example-list.ts
@@ -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 {Component, Input} from '@angular/core';
+import {EXAMPLE_COMPONENTS} from '@angular/material-examples';
+
+/** Displays a set of material examples in a mat-accordion. */
+@Component({
+ selector: 'material-example-list',
+ template: `
+
{{type}} Examples
+
+
+
+ {{id}}: {{exampleComponents[id].title}}
+
+
+
+
+
+
+ `,
+ styles: [`
+ h2 {
+ text-transform: capitalize;
+ }
+ `]
+})
+export class ExampleList {
+ /** Type of examples being displayed. */
+ @Input() type: string;
+
+ /** IDs of the examples to display. */
+ @Input() ids: string[];
+
+ exampleComponents = EXAMPLE_COMPONENTS;
+}
diff --git a/src/demo-app/example/example-module.ts b/src/demo-app/example/example-module.ts
new file mode 100644
index 000000000000..96848bec7d1a
--- /dev/null
+++ b/src/demo-app/example/example-module.ts
@@ -0,0 +1,21 @@
+/**
+ * @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 {CommonModule} from '@angular/common';
+import {MatExpansionModule} from '@angular/material';
+import {NgModule} from '@angular/core';
+
+import {ExampleList} from './example-list';
+import {Example} from './example';
+
+@NgModule({
+ imports: [MatExpansionModule, CommonModule],
+ declarations: [Example, ExampleList],
+ exports: [Example, ExampleList]
+})
+export class MaterialExampleModule {}
diff --git a/src/demo-app/example/example.ts b/src/demo-app/example/example.ts
new file mode 100644
index 000000000000..7727c069e700
--- /dev/null
+++ b/src/demo-app/example/example.ts
@@ -0,0 +1,25 @@
+/**
+ * @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, ElementRef, Input} from '@angular/core';
+
+@Component({
+ selector: 'material-example',
+ template: '',
+})
+export class Example {
+ /** ID of the material example to display. */
+ @Input() id: string;
+
+ constructor(private elementRef: ElementRef) { }
+
+ ngOnInit() {
+ const element = document.createElement(this.id);
+ this.elementRef.nativeElement.appendChild(element);
+ }
+}
diff --git a/src/demo-app/examples-page/examples-page.ts b/src/demo-app/examples-page/examples-page.ts
new file mode 100644
index 000000000000..27a9e9caf744
--- /dev/null
+++ b/src/demo-app/examples-page/examples-page.ts
@@ -0,0 +1,18 @@
+/**
+ * @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} from '@angular/core';
+import {EXAMPLE_COMPONENTS} from '@angular/material-examples';
+
+/** Renders all material examples listed in the generated EXAMPLE_COMPONENTS. */
+@Component({
+ template: ``
+})
+export class ExamplesPage {
+ examples = Object.keys(EXAMPLE_COMPONENTS);
+}
diff --git a/src/demo-app/index.html b/src/demo-app/index.html
index de018522783e..4d91dec4723c 100644
--- a/src/demo-app/index.html
+++ b/src/demo-app/index.html
@@ -11,6 +11,13 @@
+
+
+
diff --git a/src/demo-app/system-config.ts b/src/demo-app/system-config.ts
index d92d5c3683e5..a05cc0496902 100644
--- a/src/demo-app/system-config.ts
+++ b/src/demo-app/system-config.ts
@@ -27,6 +27,7 @@ System.config({
'@angular/compiler': 'node:@angular/compiler/bundles/compiler.umd.js',
'@angular/forms': 'node:@angular/forms/bundles/forms.umd.js',
'@angular/animations': 'node:@angular/animations/bundles/animations.umd.js',
+ '@angular/elements': 'node:@angular/elements/bundles/elements.umd.js',
'@angular/router': 'node:@angular/router/bundles/router.umd.js',
'@angular/animations/browser': 'node:@angular/animations/bundles/animations-browser.umd.js',
'@angular/platform-browser/animations':
@@ -39,6 +40,7 @@ System.config({
// TODO(devversion): replace once the index.ts file for the Material package has been added.
'@angular/material': 'dist/packages/material/public-api.js',
'@angular/material-experimental': 'dist/packages/material-experimental/index.js',
+ '@angular/material-examples': 'dist/packages/material-examples/index.js',
'@angular/material-moment-adapter': 'dist/packages/material-moment-adapter/index.js',
'@angular/cdk': 'dist/packages/cdk/index.js',
'@angular/cdk-experimental': 'dist/packages/cdk-experimental/index.js',
diff --git a/src/demo-app/tsconfig-aot.json b/src/demo-app/tsconfig-aot.json
index 3f9f7d9843ca..1ed79d30f9e5 100644
--- a/src/demo-app/tsconfig-aot.json
+++ b/src/demo-app/tsconfig-aot.json
@@ -22,7 +22,8 @@
"@angular/material-experimental": ["../../dist/releases/material-experimental"],
"@angular/cdk-experimental/*": ["../../dist/releases/cdk-experimental/*"],
"@angular/cdk-experimental": ["../../dist/releases/cdk-experimental"],
- "@angular/material-moment-adapter": ["../../dist/releases/material-moment-adapter"]
+ "@angular/material-moment-adapter": ["../../dist/releases/material-moment-adapter"],
+ "@angular/material-examples": ["../../dist/packages/material-examples"]
}
},
"files": [
diff --git a/src/demo-app/tsconfig-build.json b/src/demo-app/tsconfig-build.json
index 970698b31d85..e020a2e367fd 100644
--- a/src/demo-app/tsconfig-build.json
+++ b/src/demo-app/tsconfig-build.json
@@ -32,7 +32,8 @@
"@angular/material-experimental": ["../../dist/packages/material-experimental"],
"@angular/cdk-experimental/*": ["../../dist/packages/cdk-experimental/*"],
"@angular/cdk-experimental": ["../../dist/packages/cdk-experimental"],
- "@angular/material-moment-adapter": ["../../dist/packages/material-moment-adapter"]
+ "@angular/material-moment-adapter": ["../../dist/packages/material-moment-adapter"],
+ "@angular/material-examples": ["../../dist/packages/material-examples"]
}
},
"files": [
diff --git a/src/demo-app/tsconfig.json b/src/demo-app/tsconfig.json
index 743af61b5399..d09e8f865c06 100644
--- a/src/demo-app/tsconfig.json
+++ b/src/demo-app/tsconfig.json
@@ -14,7 +14,8 @@
"@angular/material-experimental": ["../material-experimental"],
"@angular/cdk-experimental/*": ["../cdk-experimental/*"],
"@angular/cdk-experimental": ["../cdk-experimental"],
- "@angular/material-moment-adapter": ["../material-moment-adapter/public-api.ts"]
+ "@angular/material-moment-adapter": ["../material-moment-adapter/public-api.ts"],
+ "@angular/material-examples": ["../../dist/packages/material-examples"]
}
},
"include": ["./**/*.ts"]
diff --git a/src/material-examples/tsconfig-tests.json b/src/material-examples/tsconfig-tests.json
new file mode 100644
index 000000000000..121ad1042807
--- /dev/null
+++ b/src/material-examples/tsconfig-tests.json
@@ -0,0 +1,22 @@
+// TypeScript config file that extends the default build tsconfig file. This config is used to
+// also compile the unit-test files. Since the code will run inside of the browser, the target is
+// set to ES5. Also the format needs to be CommonJS for Karma.
+{
+ "extends": "./tsconfig-build",
+ "compilerOptions": {
+ "importHelpers": false,
+ "module": "commonjs",
+ "target": "es5",
+ "types": ["jasmine"]
+ },
+ "angularCompilerOptions": {
+ "strictMetadataEmit": false, // Workaround for Angular #22210
+ "skipTemplateCodegen": true,
+ "emitDecoratorMetadata": true,
+ "fullTemplateTypeCheck": true
+ },
+ "include": [
+ "**/*.spec.ts",
+ "index.ts"
+ ]
+}
diff --git a/tools/gulp/tasks/aot.ts b/tools/gulp/tasks/aot.ts
index 248491c1d27f..99357a014367 100644
--- a/tools/gulp/tasks/aot.ts
+++ b/tools/gulp/tasks/aot.ts
@@ -18,7 +18,10 @@ task('aot:deps', sequenceTask(
'material:build-release',
'cdk-experimental:build-release',
'material-experimental:build-release',
- 'material-moment-adapter:build-release'
+ 'material-moment-adapter:build-release',
+ // The examples module needs to be built before building examples package
+ 'build-examples-module',
+ 'material-examples:build-release',
],
// Build the assets after the releases have been built, because the demo-app assets import
// SCSS files from the release packages.
diff --git a/tools/gulp/tasks/development.ts b/tools/gulp/tasks/development.ts
index 679f1b05c2e6..72f60971bf1a 100644
--- a/tools/gulp/tasks/development.ts
+++ b/tools/gulp/tasks/development.ts
@@ -9,7 +9,8 @@ import {
materialExperimentalPackage,
cdkExperimentalPackage,
materialPackage,
- momentAdapterPackage
+ momentAdapterPackage,
+ examplesPackage,
} from '../packages';
// These imports don't have any typings provided.
@@ -34,6 +35,7 @@ const appVendors = [
'web-animations-js',
'moment',
'tslib',
+ '@webcomponents',
];
/** Glob that matches all required vendors for the demo-app. */
@@ -58,6 +60,7 @@ task(':watch:devapp', () => {
['material-experimental:build-no-bundles']);
watchFiles(join(cdkExperimentalPackage.sourceDir, '**/*'),
['cdk-experimental:build-no-bundles']);
+ watchFiles(join(examplesPackage.sourceDir, '**/*'), ['material-examples:build-no-bundles']);
});
/** Path to the demo-app tsconfig file. */
@@ -81,6 +84,8 @@ task('build:devapp', sequenceTask(
'cdk-experimental:build-no-bundles',
'material-experimental:build-no-bundles',
'material-moment-adapter:build-no-bundles',
+ 'build-examples-module', // The examples module needs to be built before building examples package
+ 'material-examples:build-no-bundles',
[':build:devapp:assets', ':build:devapp:scss', ':build:devapp:ts']
));
@@ -98,6 +103,10 @@ task('stage-deploy:devapp', ['build:devapp'], () => {
join(outDir, 'dist/packages/cdk-experimental'));
copyFiles(materialPackage.outputDir, '**/prebuilt/*.+(css|map)',
join(outDir, 'dist/packages/material'));
+ copyFiles(examplesPackage.outputDir, '**/*.+(js|map)',
+ join(outDir, 'dist/packages/material-examples'));
+ copyFiles(momentAdapterPackage.outputDir, '**/*.+(js|map)',
+ join(outDir, 'dist/packages/material-moment-adapter'));
});
/**