feat(elements): George's comments (#22413)

PR Close #22413
This commit is contained in:
Andrew Seguin 2018-03-02 10:08:16 -08:00 committed by Miško Hevery
parent 19368085aa
commit 46efd4b938
22 changed files with 81 additions and 222 deletions

View File

@ -40,7 +40,7 @@ filegroup(
"reflect-metadata",
"source-map-support",
"minimist",
"@webcomponents/webcomponentsjs",
"@webcomponents/custom-elements",
"tslib",
] for ext in [
"*.js",

View File

@ -15,7 +15,6 @@ detection APIs.
```ts
//hello-world.ts
import { Component, Input, NgModule } from '@angular/core';
import { createNgElementConstructor, getConfigFromComponentFactory } from '@angular/elements';
@Component({
selector: 'hello-world',
@ -37,7 +36,7 @@ export class HelloWorldModule {}
import { Component, NgModuleRef } from '@angular/core';
import { createNgElementConstructor } from '@angular/elements';
import { HelloWorld } from './hello-world.ngfactory';
import { HelloWorld } from './hello-world';
@Component({
selector: 'app-root',
@ -45,9 +44,8 @@ import { HelloWorld } from './hello-world.ngfactory';
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(ngModuleRef: NgModuleRef) {
const ngElementConfig = getConfigFromComponentFactory(HelloWorld, injector);
const NgElementConstructor = createNgElementConstructor(ngElementConfig);
constructor(injector: Injector) {
const NgElementConstructor = createNgElementConstructor(HelloWorld, {injector});
customElements.register('hello-world', NgElementConstructor);
}
}

View File

@ -198,7 +198,7 @@
"url": "guide/structural-directives",
"title": "Structural Directives",
"tooltip": "Structural directives manipulate the layout of the page."
},
},
{
"url": "guide/pipes",
"title": "Pipes",
@ -458,9 +458,9 @@
]
},
{
"url": "guide/elements",
"title": "Elements",
"tooltip": "Exporting Angular Components as Web Components"
"url": "guide/custom-elements",
"title": "Custom Elements",
"tooltip": "Using Angular Components as Custom Elements."
},
{
"title": "Service Workers",

View File

@ -51,7 +51,7 @@ export const ELEMENT_MODULE_PATHS_AS_ROUTES = [
* a custom element.
*/
export interface WithCustomElementComponent {
customElementComponent: Type<string>;
customElementComponent: Type<any>;
}
/** Injection token to provide the element path modules. */

View File

@ -23,8 +23,8 @@ class FakeComponentFactory extends ComponentFactory<any> {
create(injector: Injector,
projectableNodes?: any[][],
rootSelectorOrNode?: string | any,
ngModule?: NgModuleRef<any>): ComponentRef<string> {
return jasmine.createSpyObj('ComponentRef', ['methods']);
ngModule?: NgModuleRef<any>): ComponentRef<any> {
return (jasmine.createSpy('ComponentRef') as any) as ComponentRef<any>;
};
}
@ -32,7 +32,7 @@ const FAKE_COMPONENT_FACTORIES = new Map([
['element-a-module-path', new FakeComponentFactory('element-a-input')]
]);
describe('ElementsLoader', () => {
fdescribe('ElementsLoader', () => {
let elementsLoader: ElementsLoader;
let injectedModuleRef: NgModuleRef<any>;
let fakeCustomElements;
@ -87,7 +87,7 @@ describe('ElementsLoader', () => {
elementsLoader.loadContainingCustomElements(hostEl);
tick(); // Tick for the module factory loader's async `load` function
// Call again to to check how many times registerAsCustomElements was called.
// Call again to to check how many times customElements.define was called.
elementsLoader.loadContainingCustomElements(hostEl);
tick(); // Tick for the module factory loader's async `load` function

View File

@ -32,8 +32,6 @@ export class ElementsLoader {
if (!selectors.length) { return of(null); }
selectors.forEach(s => this.register(s));
// Returns observable that completes when all discovered elements have been registered.
return fromPromise(Promise.all(selectors.map(s => this.register(s))).then(result => null));
}

View File

@ -3,7 +3,7 @@ import {Component, Input} from '@angular/core';
/** Custom element wrapper for the material expansion panel with a title input. */
@Component({
selector: 'expandable-section',
selector: 'aio-expandable-section',
templateUrl: 'expandable-section.component.html',
})
export class ExpandableSectionComponent {

View File

@ -49,7 +49,6 @@
"@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",

View File

@ -13,7 +13,8 @@
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",
"@angular/platform-browser": "0.0.0-PLACEHOLDER"
"@angular/platform-browser": "0.0.0-PLACEHOLDER",
"rxjs": "^5.5.0"
},
"repository": {
"type": "git",

View File

@ -12,7 +12,7 @@
* Entry point for all public APIs of the `elements` package.
*/
export {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from './src/element-strategy';
export {NgElement, NgElementConfig, NgElementConstructor, createNgElementConstructor} from './src/ng-element-constructor';
export {NgElement, NgElementConfig, NgElementConstructor, WithProperties, createNgElementConstructor} from './src/ng-element-constructor';
export {VERSION} from './src/version';
// This file only reexports content of the `src` folder. Keep it that way.

View File

@ -104,7 +104,7 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
* Returns the component property value. If the component has not yet been created, the value is
* retrieved from the cached initialization values.
*/
getPropertyValue(property: string): any {
getInputValue(property: string): any {
if (!this.componentRef) {
return this.initialInputValues.get(property);
}
@ -116,8 +116,8 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
* Sets the input value for the property. If the component has not yet been created, the value is
* cached and set when the component is created.
*/
setPropertyValue(property: string, value: any): void {
if (strictEquals(value, this.getPropertyValue(property))) {
setInputValue(property: string, value: any): void {
if (strictEquals(value, this.getInputValue(property))) {
return;
}
@ -158,7 +158,7 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
this.componentFactory.inputs.forEach(({propName}) => {
const initialValue = this.initialInputValues.get(propName);
if (initialValue) {
this.setPropertyValue(propName, initialValue);
this.setInputValue(propName, initialValue);
} else {
// Keep track of inputs that were not initialized in case we need to know this for
// calling ngOnChanges with SimpleChanges
@ -185,8 +185,11 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
return;
}
(this.componentRef !.instance as any as OnChanges).ngOnChanges(this.inputChanges);
// Cache the changes and set inputChanges to null to capture any changes that might occur
// during ngOnChanges.
const inputChanges = this.inputChanges;
this.inputChanges = null;
(this.componentRef !.instance as any as OnChanges).ngOnChanges(inputChanges);
}
/**
@ -199,8 +202,8 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
}
this.scheduledChangeDetectionFn = scheduler.scheduleBeforeRender(() => {
this.detectChanges();
this.scheduledChangeDetectionFn = null;
this.detectChanges();
});
}
@ -209,7 +212,7 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
*/
protected recordInputChange(property: string, currentValue: any): void {
// Do not record the change if the component does not implement `OnChanges`.
if (!this.componentRef || !this.implementsOnChanges) {
if (this.componentRef && !this.implementsOnChanges) {
return;
}
@ -228,7 +231,7 @@ export class ComponentFactoryNgElementStrategy implements NgElementStrategy {
const isFirstChange = this.uninitializedInputs.has(property);
this.uninitializedInputs.delete(property);
const previousValue = isFirstChange ? undefined : this.getPropertyValue(property);
const previousValue = isFirstChange ? undefined : this.getInputValue(property);
this.inputChanges[property] = new SimpleChange(previousValue, currentValue, isFirstChange);
}

View File

@ -29,8 +29,8 @@ export interface NgElementStrategy {
connect(element: HTMLElement): void;
disconnect(): void;
getPropertyValue(propName: string): any;
setPropertyValue(propName: string, value: string): void;
getInputValue(propName: string): any;
setInputValue(propName: string, value: string): void;
}
/**

View File

@ -42,6 +42,8 @@ export abstract class NgElement extends HTMLElement {
/**
* Additional type information that can be added to the NgElement class for properties added based
* on the inputs and methods of the underlying component.
*
* @experimental
*/
export type WithProperties<P> = {
[property in keyof P]: P[property]
@ -59,14 +61,14 @@ export interface NgElementConfig {
injector: Injector;
strategyFactory?: NgElementStrategyFactory;
propertyInputs?: string[];
attributeToPropertyInputs?: Map<string, string>;
attributeToPropertyInputs?: {[key: string]: string};
}
/** Gets a map of default set of attributes to observe and the properties they affect. */
function getDefaultAttributeToPropertyInputs(inputs: {propName: string, templateName: string}[]) {
const attributeToPropertyInputs = new Map<string, string>();
const attributeToPropertyInputs: {[key: string]: string} = {};
inputs.forEach(({propName, templateName}) => {
attributeToPropertyInputs.set(camelToDashCase(templateName), propName);
attributeToPropertyInputs[camelToDashCase(templateName)] = propName;
});
return attributeToPropertyInputs;
@ -100,7 +102,7 @@ export function createNgElementConstructor<P>(
config.attributeToPropertyInputs || getDefaultAttributeToPropertyInputs(inputs);
class NgElementImpl extends NgElement {
static readonly observedAttributes = Array.from(attributeToPropertyInputs.keys());
static readonly observedAttributes = Object.keys(attributeToPropertyInputs);
constructor(strategyFactoryOverride?: NgElementStrategyFactory) {
super();
@ -113,16 +115,16 @@ export function createNgElementConstructor<P>(
attributeChangedCallback(
attrName: string, oldValue: string|null, newValue: string, namespace?: string): void {
const propName = attributeToPropertyInputs.get(attrName) !;
this.ngElementStrategy.setPropertyValue(propName, newValue);
const propName = attributeToPropertyInputs[attrName] !;
this.ngElementStrategy.setInputValue(propName, newValue);
}
connectedCallback(): void {
// Take element attribute inputs and set them as inputs on the strategy
attributeToPropertyInputs.forEach((propName, attrName) => {
const value = this.getAttribute(attrName);
if (value) {
this.ngElementStrategy.setPropertyValue(propName, value);
NgElementImpl.observedAttributes.forEach(attrName => {
const propName = attributeToPropertyInputs[attrName] !;
if (this.hasAttribute(attrName)) {
this.ngElementStrategy.setInputValue(propName, this.getAttribute(attrName) !);
}
});
@ -150,8 +152,8 @@ export function createNgElementConstructor<P>(
const propertyInputs = config.propertyInputs || inputs.map(({propName}) => propName);
propertyInputs.forEach(property => {
Object.defineProperty(NgElementImpl.prototype, property, {
get: function() { return this.ngElementStrategy.getPropertyValue(property); },
set: function(newValue: any) { this.ngElementStrategy.setPropertyValue(property, newValue); },
get: function() { return this.ngElementStrategy.getInputValue(property); },
set: function(newValue: any) { this.ngElementStrategy.setInputValue(property, newValue); },
configurable: true,
enumerable: true,
});

View File

@ -6,12 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
* Entry point for all public APIs of the common package.
*/
import {Version} from '@angular/core';
/**
* @experimental

View File

@ -12,7 +12,6 @@ ts_library(
"//packages/core",
"//packages/core/testing",
"//packages/elements",
"//packages/elements/testing",
"//packages/platform-browser",
"//packages/platform-browser-dynamic",
"//packages/platform-browser-dynamic/testing",
@ -25,7 +24,7 @@ filegroup(
name = "elements_test_bootstrap_scripts",
# do not sort
srcs = [
"//:node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
"//:node_modules/@webcomponents/custom-elements/src/native-shim.js",
"//:node_modules/reflect-metadata/Reflect.js",
"//:node_modules/zone.js/dist/zone.js",
"//:node_modules/zone.js/dist/async-test.js",

View File

@ -40,7 +40,7 @@ describe('ComponentFactoryNgElementStrategy', () => {
describe('after connected', () => {
beforeEach(() => {
// Set up an initial value to make sure it is passed to the component
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
strategy.connect(document.createElement('div'));
});
@ -65,7 +65,7 @@ describe('ComponentFactoryNgElementStrategy', () => {
});
it('should initialize the component with initial values', () => {
expect(strategy.getPropertyValue('fooFoo')).toBe('fooFoo-1');
expect(strategy.getInputValue('fooFoo')).toBe('fooFoo-1');
expect(componentRef.instance.fooFoo).toBe('fooFoo-1');
});
@ -85,15 +85,15 @@ describe('ComponentFactoryNgElementStrategy', () => {
describe('when inputs change and not connected', () => {
it('should cache the value', () => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
expect(strategy.getPropertyValue('fooFoo')).toBe('fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
expect(strategy.getInputValue('fooFoo')).toBe('fooFoo-1');
// Sanity check: componentRef isn't changed since its not even on the strategy
expect(componentRef.instance.fooFoo).toBe(undefined);
});
it('should not detect changes', fakeAsync(() => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(0);
}));
@ -103,16 +103,16 @@ describe('ComponentFactoryNgElementStrategy', () => {
beforeEach(() => { strategy.connect(document.createElement('div')); });
it('should be set on the component instance', () => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
expect(componentRef.instance.fooFoo).toBe('fooFoo-1');
expect(strategy.getPropertyValue('fooFoo')).toBe('fooFoo-1');
expect(strategy.getInputValue('fooFoo')).toBe('fooFoo-1');
});
it('should detect changes', fakeAsync(() => {
// Connect detected changes automatically
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(1);
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(2);
}));
@ -121,14 +121,14 @@ describe('ComponentFactoryNgElementStrategy', () => {
// Connect detected changes automatically
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(1);
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setPropertyValue('barBar', 'barBar-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('barBar', 'barBar-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(2);
}));
it('should call ngOnChanges', fakeAsync(() => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expectSimpleChanges(
componentRef.instance.simpleChanges[0],
@ -136,8 +136,8 @@ describe('ComponentFactoryNgElementStrategy', () => {
}));
it('should call ngOnChanges once for multiple input changes', fakeAsync(() => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setPropertyValue('barBar', 'barBar-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('barBar', 'barBar-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expectSimpleChanges(componentRef.instance.simpleChanges[0], {
fooFoo: new SimpleChange(undefined, 'fooFoo-1', true),
@ -147,16 +147,16 @@ describe('ComponentFactoryNgElementStrategy', () => {
it('should call ngOnChanges twice for changes in different rounds with previous values',
fakeAsync(() => {
strategy.setPropertyValue('fooFoo', 'fooFoo-1');
strategy.setPropertyValue('barBar', 'barBar-1');
strategy.setInputValue('fooFoo', 'fooFoo-1');
strategy.setInputValue('barBar', 'barBar-1');
tick(16); // scheduler waits 16ms if RAF is unavailable
expectSimpleChanges(componentRef.instance.simpleChanges[0], {
fooFoo: new SimpleChange(undefined, 'fooFoo-1', true),
barBar: new SimpleChange(undefined, 'barBar-1', true)
});
strategy.setPropertyValue('fooFoo', 'fooFoo-2');
strategy.setPropertyValue('barBar', 'barBar-2');
strategy.setInputValue('fooFoo', 'fooFoo-2');
strategy.setInputValue('barBar', 'barBar-2');
tick(16); // scheduler waits 16ms if RAF is unavailable
expectSimpleChanges(componentRef.instance.simpleChanges[1], {
fooFoo: new SimpleChange('fooFoo-1', 'fooFoo-2', false),

View File

@ -13,7 +13,6 @@ import {Subject} from 'rxjs/Subject';
import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from '../src/element-strategy';
import {NgElementConstructor, createNgElementConstructor} from '../src/ng-element-constructor';
import {patchEnv, restoreEnv} from '../testing/index';
type WithFooBar = {
fooFoo: string,
@ -27,7 +26,6 @@ if (typeof customElements !== 'undefined') {
let strategyFactory: TestStrategyFactory;
let injector: Injector;
beforeAll(() => patchEnv());
beforeAll(done => {
destroyPlatform();
platformBrowserDynamic()
@ -47,7 +45,6 @@ if (typeof customElements !== 'undefined') {
});
afterAll(() => destroyPlatform());
afterAll(() => restoreEnv());
it('should use a default strategy for converting component inputs', () => {
expect(NgElementCtor.observedAttributes).toEqual(['foo-foo', 'barbar']);
@ -60,8 +57,8 @@ if (typeof customElements !== 'undefined') {
element.connectedCallback();
expect(strategy.connectedElement).toBe(element);
expect(strategy.getPropertyValue('fooFoo')).toBe('value-foo-foo');
expect(strategy.getPropertyValue('barBar')).toBe('value-barbar');
expect(strategy.getInputValue('fooFoo')).toBe('value-foo-foo');
expect(strategy.getInputValue('barBar')).toBe('value-barbar');
});
it('should listen to output events after connected', () => {
@ -108,8 +105,7 @@ if (typeof customElements !== 'undefined') {
injector,
strategyFactory,
propertyInputs: ['prop1', 'prop2'],
attributeToPropertyInputs:
new Map<string, string>([['attr-1', 'prop1'], ['attr-2', 'prop2']])
attributeToPropertyInputs: {'attr-1': 'prop1', 'attr-2': 'prop2'}
});
customElements.define('test-element-with-changed-attributes', NgElementCtorWithChangedAttr);
@ -128,9 +124,9 @@ if (typeof customElements !== 'undefined') {
element.setAttribute('attr-3', 'value-3'); // Made-up attribute
element.connectedCallback();
expect(strategy.getPropertyValue('prop1')).toBe('value-1');
expect(strategy.getPropertyValue('prop2')).toBe('value-2');
expect(strategy.getPropertyValue('prop3')).not.toBe('value-3');
expect(strategy.getInputValue('prop1')).toBe('value-1');
expect(strategy.getInputValue('prop2')).toBe('value-2');
expect(strategy.getInputValue('prop3')).not.toBe('value-3');
});
});
});
@ -169,9 +165,9 @@ export class TestStrategy implements NgElementStrategy {
disconnect(): void { this.disconnectCalled = true; }
getPropertyValue(propName: string): any { return this.inputs.get(propName); }
getInputValue(propName: string): any { return this.inputs.get(propName); }
setPropertyValue(propName: string, value: string): void { this.inputs.set(propName, value); }
setInputValue(propName: string, value: string): void { this.inputs.set(propName, value); }
}
export class TestStrategyFactory implements NgElementStrategyFactory {

View File

@ -1,19 +0,0 @@
package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "ts_library")
ts_library(
name = "testing",
srcs = glob(
[
"*.ts",
],
),
module_name = "@angular/elements/testing",
deps = [
"//packages/core",
"//packages/elements",
"//packages/platform-browser",
"@rxjs",
],
)

View File

@ -1,115 +0,0 @@
/**
* @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
*/
import {scheduler} from '../src/utils';
export interface MockScheduler {
schedule: (typeof scheduler)['schedule'];
scheduleBeforeRender: (typeof scheduler)['scheduleBeforeRender'];
}
export class AsyncMockScheduler implements MockScheduler {
private uid = 0;
private pendingBeforeRenderCallbacks: ({id: number, cb: () => void})[] = [];
private pendingDelayedCallbacks: ({id: number, cb: () => void, delay: number})[] = [];
flushBeforeRender(): void {
while (this.pendingBeforeRenderCallbacks.length) {
const cb = this.pendingBeforeRenderCallbacks.shift() !.cb;
cb();
}
}
reset(): void {
this.pendingBeforeRenderCallbacks.length = 0;
this.pendingDelayedCallbacks.length = 0;
}
schedule(cb: () => void, delay: number): () => void {
const id = ++this.uid;
let idx = this.pendingDelayedCallbacks.length;
for (let i = this.pendingDelayedCallbacks.length - 1; i >= 0; --i) {
if (this.pendingDelayedCallbacks[i].delay <= delay) {
idx = i + 1;
break;
}
}
this.pendingDelayedCallbacks.splice(idx, 0, {id, cb, delay});
return () => this.remove(id, this.pendingDelayedCallbacks);
}
scheduleBeforeRender(cb: () => void): () => void {
const id = ++this.uid;
this.pendingBeforeRenderCallbacks.push({id, cb});
return () => this.remove(id, this.pendingBeforeRenderCallbacks);
}
tick(ms: number): void {
this.flushBeforeRender();
this.pendingDelayedCallbacks.forEach(item => item.delay -= ms);
this.pendingDelayedCallbacks = this.pendingDelayedCallbacks.filter(item => {
if (item.delay <= 0) {
const cb = item.cb;
cb();
return false;
}
return true;
});
}
private remove(id: number, items: {id: number}[]): void {
for (let i = 0, ii = items.length; i < ii; ++i) {
if (items[i].id === id) {
items.splice(i, 1);
break;
}
}
}
}
export class SyncMockScheduler implements MockScheduler {
schedule(cb: () => void, delay: number): () => void {
cb();
return () => undefined;
}
scheduleBeforeRender(cb: () => void): () => void {
cb();
return () => undefined;
}
}
export function installMockScheduler(isSync?: false): AsyncMockScheduler;
export function installMockScheduler(isSync: true): SyncMockScheduler;
export function installMockScheduler(isSync?: boolean): AsyncMockScheduler|SyncMockScheduler {
const mockScheduler = isSync ? new SyncMockScheduler() : new AsyncMockScheduler();
Object.keys(scheduler).forEach((method: keyof typeof scheduler) => {
spyOn(scheduler, method).and.callFake(mockScheduler[method].bind(mockScheduler));
});
return mockScheduler;
}
export function patchEnv() {
// This helper function is defined in `test-main.js`. See there for more details.
// (//window as any).$$patchInnerHtmlProp();
}
export function restoreEnv() {
// This helper function is defined in `test-main.js`. See there for more details.
//(window as any).$$restoreInnerHtmlProp();
}
export function supportsCustomElements() {
// The browser does not natively support custom elements and is not polyfillable.
return typeof customElements !== 'undefined';
}

View File

@ -76,7 +76,7 @@ Promise
.resolve()
// Load browser-specific polyfills for custom elements.
.then(function() { return loadCustomElementsPolyfills(); })
// .then(function() { return loadCustomElementsPolyfills(); })
// Load necessary testing packages.
.then(function() {

View File

@ -12,7 +12,9 @@ export declare abstract class NgElement extends HTMLElement {
/** @experimental */
export interface NgElementConfig {
attributeToPropertyInputs?: Map<string, string>;
attributeToPropertyInputs?: {
[key: string]: string;
};
injector: Injector;
propertyInputs?: string[];
strategyFactory?: NgElementStrategyFactory;
@ -29,8 +31,8 @@ export interface NgElementStrategy {
events: Observable<NgElementStrategyEvent>;
connect(element: HTMLElement): void;
disconnect(): void;
getPropertyValue(propName: string): any;
setPropertyValue(propName: string, value: string): void;
getInputValue(propName: string): any;
setInputValue(propName: string, value: string): void;
}
/** @experimental */
@ -46,3 +48,8 @@ export interface NgElementStrategyFactory {
/** @experimental */
export declare const VERSION: Version;
/** @experimental */
export declare type WithProperties<P> = {
[property in keyof P]: P[property];
};

View File

@ -160,10 +160,6 @@
version "1.0.8"
resolved "https://registry.yarnpkg.com/@webcomponents/custom-elements/-/custom-elements-1.0.8.tgz#b7b8ef7248f7681d1ad4286a0ada5fe3c2bc7228"
"@webcomponents/webcomponentsjs@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.1.0.tgz#1392799c266fca142622a720176f688beb74d181"
Base64@~0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028"