Skip to content
Permalink
Browse files

feat(elements): add support for creating custom elements (#22413)

PR Close #22413
  • Loading branch information...
andrewseguin authored and mhevery committed Feb 28, 2018
1 parent cedc04c commit 22b96b96902e1a42ee8c5e807720424abad3082a
Showing with 1,823 additions and 17 deletions.
  1. +11 −0 .pullapprove.yml
  2. +1 −0 BUILD.bazel
  3. +1 −0 CONTRIBUTING.md
  4. +67 −0 aio/content/guide/elements.md
  5. +5 −0 aio/content/navigation.json
  6. +1 −0 aio/tools/transforms/angular-api-package/index.js
  7. +3 −2 aio/tools/transforms/authors-package/api-package.js
  8. +2 −1 build.sh
  9. +9 −0 karma-js.conf.js
  10. +3 −0 package.json
  11. +19 −0 packages/elements/BUILD.bazel
  12. +14 −0 packages/elements/index.ts
  13. +22 −0 packages/elements/package.json
  14. +19 −0 packages/elements/public_api.ts
  15. +31 −0 packages/elements/rollup.config.js
  16. +262 −0 packages/elements/src/component-factory-strategy.ts
  17. +41 −0 packages/elements/src/element-strategy.ts
  18. +54 −0 packages/elements/src/extract-projectable-nodes.ts
  19. +135 −0 packages/elements/src/ng-element-constructor.ts
  20. +103 −0 packages/elements/src/utils.ts
  21. +19 −0 packages/elements/src/version.ts
  22. +49 −0 packages/elements/test/BUILD.bazel
  23. +78 −0 packages/elements/test/component-factory-strategy_spec.ts
  24. +81 −0 packages/elements/test/extract-projectable-nodes_spec.ts
  25. +186 −0 packages/elements/test/ng-element-constructor_spec.ts
  26. +231 −0 packages/elements/test/utils_spec.ts
  27. +19 −0 packages/elements/testing/BUILD.bazel
  28. +115 −0 packages/elements/testing/index.ts
  29. +27 −0 packages/elements/tsconfig-build.json
  30. +124 −14 test-main.js
  31. +1 −0 tools/cjs-jasmine/index.ts
  32. +77 −0 tools/public_api_guard/elements/elements.d.ts
  33. +1 −0 tools/validate-commit-message/commit-message.json
  34. +12 −0 yarn.lock
@@ -7,6 +7,7 @@
#
# alexeagle - Alex Eagle
# alxhub - Alex Rickabaugh
# andrewseguin - Andrew Seguin
# brocco - Mike Brocchi
# chuckjaz - Chuck Jazdzewski
# filipesilva - Filipe Silva
@@ -302,6 +303,16 @@ groups:
- IgorMinar #fallback
- mhevery #fallback

elements:
conditions:
files:
- "packages/elements/*"
users:
- andrewseguin #primary
- gkalpak
- IgorMinar #fallback
- mhevery #fallback

benchpress:
conditions:
files:
@@ -40,6 +40,7 @@ filegroup(
"reflect-metadata",
"source-map-support",
"minimist",
"@webcomponents/webcomponentsjs",
"tslib",
] for ext in [
"*.js",
@@ -212,6 +212,7 @@ The following is the list of supported scopes:
* **compiler**
* **compiler-cli**
* **core**
* **elements**
* **forms**
* **http**
* **language-service**
@@ -0,0 +1,67 @@
# Elements

## Release Status

**Angular Labs Project** - experimental and unstable. **Breaking Changes Possible**

Targeted to land in the [6.x release cycle](https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md) of Angular - subject to change

## Overview

Elements provides an API that allows developers to register Angular Components as Custom Elements
("Web Components"), and bridges the built-in DOM API to Angular's component interface and change
detection APIs.

```ts
//hello-world.ts
import { Component, Input, NgModule } from '@angular/core';
import { createNgElementConstructor, getConfigFromComponentFactory } from '@angular/elements';

This comment has been minimized.

Copy link
@unicodeveloper

unicodeveloper Apr 25, 2018

Since the API has been renamed, please can this be updated?

@Component({
selector: 'hello-world',
template: `<h1>Hello {{name}}</h1>`
})
export class HelloWorld {
@Input() name: string = 'World!';
}
@NgModule({
declarations: [ HelloWorld ],
entryComponents: [ HelloWorld ]
})
export class HelloWorldModule {}
```

```ts
//app.component.ts
import { Component, NgModuleRef } from '@angular/core';
import { createNgElementConstructor } from '@angular/elements';
import { HelloWorld } from './hello-world.ngfactory';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(ngModuleRef: NgModuleRef) {
const ngElementConfig = getConfigFromComponentFactory(HelloWorld, injector);
const NgElementConstructor = createNgElementConstructor(ngElementConfig);
customElements.register('hello-world', NgElementConstructor);
}
}
```
Once registered, these components can be used just like built-in HTML elements, because they *are*
HTML Elements!

They can be used in any HTML page:

```html
<hello-world name="Angular"></hello-world>
<hello-world name="Typescript"></hello-world>
```

Custom Elements are "self-bootstrapping" - they are automatically started when they are added to the
DOM, and automatically destroyed when removed from the DOM.
@@ -457,6 +457,11 @@
}
]
},
{
"url": "guide/elements",
"title": "Elements",
"tooltip": "Exporting Angular Components as Web Components"
},
{
"title": "Service Workers",
"tooltip": "Angular service workers: Controlling caching of application resources.",
@@ -73,6 +73,7 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage])
'common/testing/index.ts',
'core/index.ts',
'core/testing/index.ts',
'elements/index.ts',
'forms/index.ts',
'http/index.ts',
'http/testing/index.ts',
@@ -11,15 +11,16 @@ const { API_SOURCE_PATH } = require('../config');

const packageMap = {
animations: ['animations/index.ts', 'animations/browser/index.ts', 'animations/browser/testing/index.ts'],
common: ['common/index.ts', 'common/testing/index.ts'],
common: ['common/index.ts', 'common/testing/index.ts', 'common/http/index.ts', 'common/http/testing/index.ts'],
core: ['core/index.ts', 'core/testing/index.ts'],
elements: ['elements/index.ts'],
forms: ['forms/index.ts'],
http: ['http/index.ts', 'http/testing/index.ts'],
'platform-browser': ['platform-browser/index.ts', 'platform-browser/animations/index.ts', 'platform-browser/testing/index.ts'],
'platform-browser-dynamic': ['platform-browser-dynamic/index.ts', 'platform-browser-dynamic/testing/index.ts'],
'platform-server': ['platform-server/index.ts', 'platform-server/testing/index.ts'],
'platform-webworker': ['platform-webworker/index.ts'],
'platform-webworker-dynamic': 'platform-webworker-dynamic/index.ts',
'platform-webworker-dynamic': ['platform-webworker-dynamic/index.ts'],
router: ['router/index.ts', 'router/testing/index.ts', 'router/upgrade/index.ts'],
'service-worker': ['service-worker/index.ts'],
upgrade: ['upgrade/index.ts', 'upgrade/static/index.ts']
@@ -24,7 +24,8 @@ PACKAGES=(core
compiler-cli
language-service
benchpress
service-worker)
service-worker
elements)

TSC_PACKAGES=(compiler-cli
language-service
@@ -41,6 +41,15 @@ module.exports = function(config) {
'test-events.js',
'shims_for_IE.js',
'node_modules/systemjs/dist/system.src.js',

// Serve polyfills necessary for testing the `elements` package.
{
pattern: 'node_modules/@webcomponents/custom-elements/**/*.js',
included: false,
watched: false
},
{pattern: 'node_modules/mutation-observer/index.js', included: false, watched: false},

{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
@@ -48,6 +48,8 @@
"@types/shelljs": "^0.7.8",
"@types/source-map": "^0.5.1",
"@types/systemjs": "0.19.32",
"@webcomponents/custom-elements": "^1.0.4",
"@webcomponents/webcomponentsjs": "^1.1.0",
"angular": "npm:angular@1.6",
"angular-1.5": "npm:angular@1.5",
"angular-mocks": "npm:angular-mocks@1.6",
@@ -87,6 +89,7 @@
"karma-sourcemap-loader": "0.3.6",
"madge": "0.5.0",
"minimist": "1.2.0",
"mutation-observer": "^1.0.3",
"node-uuid": "1.4.8",
"protractor": "5.1.2",
"rewire": "2.5.2",
@@ -0,0 +1,19 @@
package(default_visibility = ["//visibility:public"])

load("//tools:defaults.bzl", "ng_module")

ng_module(
name = "elements",
srcs = glob(
[
"*.ts",
"src/**/*.ts",
],
),
module_name = "@angular/elements",
deps = [
"//packages/core",
"//packages/platform-browser",
"@rxjs",
],
)
@@ -0,0 +1,14 @@
/**
* @license
* Copyright Google Inc. 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
*/

// This file is not used to build this module. It is only used during editing
// by the TypeScript language service and during build for verification. `ngc`
// replaces this file with production index.ts when it rewrites private symbol
// names.

export * from './public_api';
@@ -0,0 +1,22 @@
{
"name": "@angular/elements",
"version": "0.0.0-PLACEHOLDER",
"description": "Angular - library for using Angular Components as Custom Elements",
"main": "./bundles/elements.umd.js",
"module": "./esm5/elements.js",
"es2015": "./esm2015/elements.js",
"typings": "./elements.d.ts",
"author": "angular",
"license": "MIT",
"dependencies": {
"tslib": "^1.7.1"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",
"@angular/platform-browser": "0.0.0-PLACEHOLDER"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
}
}
@@ -0,0 +1,19 @@
/**
* @license
* Copyright Google Inc. 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
*/

/**
* @module
* @description
* Entry point for all public APIs of the `elements` package.
*/
export {ComponentFactoryNgElementStrategy, ComponentFactoryNgElementStrategyFactory, getConfigFromComponentFactory} from './src/component-factory-strategy';
export {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from './src/element-strategy';
export {NgElement, NgElementConfig, NgElementConstructor, createNgElementConstructor} from './src/ng-element-constructor';
export {VERSION} from './src/version';

// This file only reexports content of the `src` folder. Keep it that way.
@@ -0,0 +1,31 @@
/**
* @license
* Copyright Google Inc. 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
*/

const resolve = require('rollup-plugin-node-resolve');
const sourcemaps = require('rollup-plugin-sourcemaps');

const globals = {
'@angular/core': 'ng.core',
'@angular/platform-browser': 'ng.platformBrowser',
'rxjs/Subscription': 'Rx',
'rxjs/Observable': 'Rx',
'rxjs/observable/merge': 'Rx.Observable',
'rxjs/operator/map': 'Rx.Observable.prototype'
};

module.exports = {
entry: '../../dist/packages-dist/elements/esm5/elements.js',
dest: '../../dist/packages-dist/elements/bundles/elements.umd.js',
format: 'umd',
exports: 'named',
amd: {id: '@angular/elements'},
moduleName: 'ng.elements',
plugins: [resolve(), sourcemaps()],
external: Object.keys(globals),
globals: globals
};

0 comments on commit 22b96b9

Please sign in to comment.
You can’t perform that action at this time.