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')); }); /**