diff --git a/.circleci/config.yml b/.circleci/config.yml index e06a47bc8f..bd699f9785 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -310,9 +310,6 @@ jobs: - run: command: npm install working_directory: /tmp/workspace/angular/test/test-app - - run: - command: npm run sync - working_directory: /tmp/workspace/angular/test/test-app - run: command: npm test working_directory: /tmp/workspace/angular/test/test-app diff --git a/.scripts/common.js b/.scripts/common.js index 365182d8e9..c1621f2fec 100644 --- a/.scripts/common.js +++ b/.scripts/common.js @@ -13,7 +13,8 @@ const packages = [ 'docs', 'angular', 'packages/react', - 'packages/react-router' + 'packages/react-router', + 'packages/angular-server' ]; function readPkg(project) { @@ -151,6 +152,7 @@ function preparePackage(tasks, package, version, install) { } } + // Lint, Test, Bump Core dependency if (version) { projectTasks.push({ title: `${pkg.name}: lint`, @@ -160,12 +162,22 @@ function preparePackage(tasks, package, version, install) { title: `${pkg.name}: test`, task: async () => await execa('npm', ['test'], { cwd: projectRoot }) }); + projectTasks.push({ + title: `${pkg.name}: update ionic/core dep to ${version}`, + task: () => { + updateDependency(pkg, '@ionic/core', version); + writePkg(package, pkg); + } + }); } + // Build projectTasks.push({ title: `${pkg.name}: build`, task: () => execa('npm', ['run', 'build'], { cwd: projectRoot }) }); + + // Link core or react for sub projects if (package === 'core' || package === 'packages/react') { projectTasks.push({ title: `${pkg.name}: npm link`, @@ -236,7 +248,6 @@ function prepareDevPackage(tasks, package, version) { function updatePackageVersions(tasks, packages, version) { packages.forEach(package => { updatePackageVersion(tasks, package, version); - tasks.push({ title: `${package} update @ionic/core dependency, if present ${tc.dim(`(${version})`)}`, task: async () => { @@ -261,7 +272,11 @@ function updatePackageVersions(tasks, packages, version) { } function updatePackageVersion(tasks, package, version) { - const projectRoot = projectPath(package); + let projectRoot = projectPath(package); + + if (package === 'packages/angular-server' || package === 'angular') { + projectRoot = path.join(projectPath, 'dist') + } tasks.push({ title: `${package}: update package.json ${tc.dim(`(${version})`)}`, @@ -290,9 +305,13 @@ function publishPackages(tasks, packages, version, tag = 'latest') { }); }); - // next publish + // Publish packages.forEach(package => { - const projectRoot = projectPath(package); + let projectRoot = projectPath(package); + + if (package === 'packages/angular-server' || package === 'angular') { + projectRoot = path.join(projectRoot, 'dist') + } tasks.push({ title: `${package}: publish to ${tag} tag`, diff --git a/angular/package.json b/angular/package.json index c43fae6c70..04257a1549 100644 --- a/angular/package.json +++ b/angular/package.json @@ -24,11 +24,11 @@ }, "homepage": "https://ionicframework.com/", "scripts": { - "build": "npm run clean && npm run build.core && npm run build.ng && npm run clean-generated", + "build": "npm run clean && npm run build.ng && npm run build.core && npm run clean-generated", "build.core": "node scripts/build-core.js", "build.fesm": "rollup --config ./scripts/rollup.config.js", "build.link": "npm run build && node scripts/link-copy.js", - "build.ng": "npm run build.es2015 && npm run build.es5", + "build.ng": "ng-packagr -p package.json", "build.es2015": "ngc -p tsconfig.json && rollup --config ./scripts/rollup.config.js", "build.es5": "ngc -p tsconfig.legacy.json && rollup --config ./scripts/rollup.config.legacy.js", "clean": "node scripts/clean.js", @@ -41,53 +41,46 @@ "tsc": "tsc -p .", "validate": "npm i && npm run lint && npm run test && npm run build" }, - "module": "dist/fesm5.js", - "main": "dist/fesm5.cjs.js", - "types": "dist/core.d.ts", - "files": [ - "dist/", - "css/" - ], "dependencies": { "@ionic/core": "5.0.0-beta.2", "tslib": "^1.9.3" }, "peerDependencies": { - "@angular-devkit/core": "7.2.1 - 8", - "@angular-devkit/schematics": "7.2.1 - 8", - "@angular/core": "7.2.1 - 8", - "@angular/common": "7.2.1 - 8", - "@angular/forms": "7.2.1 - 8", - "@angular/router": "7.2.1 - 8", - "@angular/compiler": "7.2.1 - 8", - "@angular/compiler-cli": "7.2.1 - 8", - "@angular/platform-browser": "7.2.1 - 8", - "@angular/platform-browser-dynamic": "7.2.1 - 8", + "@angular/core": ">=8.2.7", + "@angular/forms": ">=8.2.7", + "@angular/router": ">=8.2.7", "rxjs": ">=6.2.0", "zone.js": ">=0.8.26" }, "devDependencies": { - "@angular-devkit/core": "^7.2.1", - "@angular-devkit/schematics": "^7.2.1", - "@angular/common": "^7.2.1", - "@angular/compiler": "^7.2.1", - "@angular/compiler-cli": "^7.2.1", - "@angular/core": "^7.2.1", - "@angular/forms": "^7.2.1", - "@angular/platform-browser": "^7.2.1", - "@angular/platform-browser-dynamic": "^7.2.1", - "@angular/router": "^7.2.1", - "@types/node": "~12.0.12", + "@angular-devkit/core": "8.3.17", + "@angular-devkit/schematics": "8.3.17", + "@angular/common": "8.2.13", + "@angular/compiler": "8.2.13", + "@angular/compiler-cli": "8.2.13", + "@angular/core": "8.2.13", + "@angular/forms": "8.2.13", + "@angular/router": "8.2.13", + "@types/node": "12.12.5", "fs-extra": "^7.0.0", "glob": "^7.1.4", + "ng-packagr": "5.7.1", "rollup": "~1.17.0", "rollup-plugin-node-resolve": "~5.2.0", "rxjs": "^6.5.2", "tsickle": "^0.34.0", "tslint": "^5.12.1", "tslint-ionic-rules": "0.0.21", - "typescript": "~3.2.2", - "zone.js": "~0.8.26" + "typescript": "3.4.5", + "zone.js": "^0.8.28" }, - "schematics": "./dist/schematics/collection.json" + "schematics": "schematics/collection.json", + "ngPackage": { + "lib": { + "entryFile": "src/index.ts" + }, + "whitelistedNonPeerDependencies": [ + "@ionic/core" + ] + } } diff --git a/angular/scripts/build-core.js b/angular/scripts/build-core.js index bc290205fb..25eed9daca 100644 --- a/angular/scripts/build-core.js +++ b/angular/scripts/build-core.js @@ -15,7 +15,7 @@ function copyIonicons() { function copyCSS() { const src = path.join(__dirname, '..', '..', 'core', 'css'); - const dst = path.join(__dirname, '..', 'css'); + const dst = path.join(__dirname, '..','dist', 'css'); fs.removeSync(dst); fs.copySync(src, dst); diff --git a/angular/scripts/rollup.config.js b/angular/scripts/rollup.config.js index 63a2793035..0a80b0c530 100644 --- a/angular/scripts/rollup.config.js +++ b/angular/scripts/rollup.config.js @@ -16,7 +16,7 @@ export default { }, plugins: [ resolve({ - module: true, + mainFields: ['module'] }) ] -}; \ No newline at end of file +}; diff --git a/angular/src/app-initialize.ts b/angular/src/app-initialize.ts index 6b3de5ae46..362a9ab5cc 100644 --- a/angular/src/app-initialize.ts +++ b/angular/src/app-initialize.ts @@ -10,7 +10,7 @@ let didInitialize = false; export const appInitialize = (config: Config, doc: Document, zone: NgZone) => { return (): any => { const win: IonicWindow | undefined = doc.defaultView as any; - if (win) { + if (win && typeof (window as any) !== 'undefined') { if (didInitialize) { console.warn('Ionic Angular was already initialized. Make sure IonicModule.forRoot() is just called once.'); } diff --git a/angular/src/directives/navigation/ion-back-button.ts b/angular/src/directives/navigation/ion-back-button.ts index 1ab072056a..2b3ec313c0 100644 --- a/angular/src/directives/navigation/ion-back-button.ts +++ b/angular/src/directives/navigation/ion-back-button.ts @@ -6,7 +6,7 @@ import { IonRouterOutlet } from './ion-router-outlet'; @Directive({ selector: 'ion-back-button', - inputs: ['defaultHref'] + inputs: ['defaultHref'], }) export class IonBackButtonDelegate { diff --git a/angular/src/directives/navigation/ion-tabs.ts b/angular/src/directives/navigation/ion-tabs.ts index 60aa2430f3..ede0d54fae 100644 --- a/angular/src/directives/navigation/ion-tabs.ts +++ b/angular/src/directives/navigation/ion-tabs.ts @@ -42,15 +42,15 @@ import { StackEvent } from './stack-utils'; }) export class IonTabs { - @ViewChild('outlet', { read: IonRouterOutlet }) outlet: IonRouterOutlet; - @ContentChild(IonTabBar) tabBar: IonTabBar | undefined; + @ViewChild('outlet', { read: IonRouterOutlet, static: false }) outlet: IonRouterOutlet; + @ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined; - @Output() ionTabsWillChange = new EventEmitter<{tab: string}>(); - @Output() ionTabsDidChange = new EventEmitter<{tab: string}>(); + @Output() ionTabsWillChange = new EventEmitter<{ tab: string }>(); + @Output() ionTabsDidChange = new EventEmitter<{ tab: string }>(); constructor( private navCtrl: NavController, - ) {} + ) { } /** * @internal diff --git a/angular/src/directives/navigation/nav-delegate.ts b/angular/src/directives/navigation/nav-delegate.ts index 9c8439a999..e12964f10d 100644 --- a/angular/src/directives/navigation/nav-delegate.ts +++ b/angular/src/directives/navigation/nav-delegate.ts @@ -1,11 +1,17 @@ import { ComponentFactoryResolver, Directive, ElementRef, Injector, ViewContainerRef } from '@angular/core'; import { AngularDelegate } from '../../providers/angular-delegate'; +import { ProxyCmp, proxyOutputs } from '../proxies-utils'; +@ProxyCmp({ + inputs: ['animated', 'animation', 'root', 'rootParams', 'swipeGesture'], + methods: ['push', 'insert', 'insertPages', 'pop', 'popTo', 'popToRoot', 'removeIndex', 'setRoot', 'setPages', 'getActive', 'getByIndex', 'canGoBack', 'getPrevious'] +}) @Directive({ - selector: 'ion-nav', + selector: 'ion-nav' }) export class NavDelegate { + protected el: HTMLElement; constructor( ref: ElementRef, resolver: ComponentFactoryResolver, @@ -13,6 +19,8 @@ export class NavDelegate { angularDelegate: AngularDelegate, location: ViewContainerRef ) { + this.el = ref.nativeElement; ref.nativeElement.delegate = angularDelegate.create(resolver, injector, location); + proxyOutputs(this, this.el, ['ionNavDidChange' , 'ionNavWillChange' ]); } } diff --git a/angular/src/directives/proxies-utils.ts b/angular/src/directives/proxies-utils.ts index 363c83bd20..f09d5efbbe 100644 --- a/angular/src/directives/proxies-utils.ts +++ b/angular/src/directives/proxies-utils.ts @@ -5,10 +5,12 @@ export const proxyInputs = (Cmp: any, inputs: string[]) => { const Prototype = Cmp.prototype; inputs.forEach(item => { Object.defineProperty(Prototype, item, { - get() { return this.el[item]; }, - set(val: any) { - this.z.runOutsideAngular(() => this.el[item] = val); + get() { + return this.el[item]; }, + set(val: any) { + this.z.runOutsideAngular(() => (this.el[item] = val)); + } }); }); }; @@ -16,13 +18,29 @@ export const proxyInputs = (Cmp: any, inputs: string[]) => { export const proxyMethods = (Cmp: any, methods: string[]) => { const Prototype = Cmp.prototype; methods.forEach(methodName => { - Prototype[methodName] = function() { + Prototype[methodName] = function () { const args = arguments; - return this.z.runOutsideAngular(() => this.el[methodName].apply(this.el, args)); + return this.z.runOutsideAngular(() => + this.el[methodName].apply(this.el, args) + ); }; }); }; export const proxyOutputs = (instance: any, el: any, events: string[]) => { events.forEach(eventName => instance[eventName] = fromEvent(el, eventName)); -}; +} + +// tslint:disable-next-line: only-arrow-functions +export function ProxyCmp(opts: { inputs?: any; methods?: any }) { + const decorator = function(cls: any){ + if (opts.inputs) { + proxyInputs(cls, opts.inputs); + } + if (opts.methods) { + proxyMethods(cls, opts.methods); + } + return cls; + }; + return decorator; +} diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index bd46019582..62dcaacc1f 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -1,11 +1,12 @@ /* tslint:disable */ /* auto-generated angular directive proxies */ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from '@angular/core'; -import { proxyInputs, proxyMethods, proxyOutputs } from './proxies-utils'; +import { ProxyCmp, proxyOutputs } from './proxies-utils'; import { Components } from '@ionic/core'; export declare interface IonApp extends Components.IonApp {} + @Component({ selector: 'ion-app', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonApp { protected el: HTMLElement; @@ -16,6 +17,7 @@ export class IonApp { } export declare interface IonAvatar extends Components.IonAvatar {} + @Component({ selector: 'ion-avatar', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonAvatar { protected el: HTMLElement; @@ -26,6 +28,7 @@ export class IonAvatar { } export declare interface IonBackButton extends Components.IonBackButton {} +@ProxyCmp({inputs: ['color', 'defaultHref', 'disabled', 'icon', 'mode', 'text', 'type']}) @Component({ selector: 'ion-back-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'defaultHref', 'disabled', 'icon', 'mode', 'text', 'type'] }) export class IonBackButton { protected el: HTMLElement; @@ -34,9 +37,9 @@ export class IonBackButton { this.el = r.nativeElement; } } -proxyInputs(IonBackButton, ['color', 'defaultHref', 'disabled', 'icon', 'mode', 'text', 'type']); export declare interface IonBackdrop extends Components.IonBackdrop {} +@ProxyCmp({inputs: ['stopPropagation', 'tappable', 'visible']}) @Component({ selector: 'ion-backdrop', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['stopPropagation', 'tappable', 'visible'] }) export class IonBackdrop { ionBackdropTap!: EventEmitter; @@ -47,9 +50,9 @@ export class IonBackdrop { proxyOutputs(this, this.el, ['ionBackdropTap']); } } -proxyInputs(IonBackdrop, ['stopPropagation', 'tappable', 'visible']); export declare interface IonBadge extends Components.IonBadge {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-badge', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonBadge { protected el: HTMLElement; @@ -58,9 +61,9 @@ export class IonBadge { this.el = r.nativeElement; } } -proxyInputs(IonBadge, ['color', 'mode']); export declare interface IonButton extends Components.IonButton {} +@ProxyCmp({inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'href', 'mode', 'rel', 'routerDirection', 'shape', 'size', 'strong', 'target', 'type']}) @Component({ selector: 'ion-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'href', 'mode', 'rel', 'routerDirection', 'shape', 'size', 'strong', 'target', 'type'] }) export class IonButton { ionFocus!: EventEmitter; @@ -72,9 +75,9 @@ export class IonButton { proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']); } } -proxyInputs(IonButton, ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'href', 'mode', 'rel', 'routerDirection', 'shape', 'size', 'strong', 'target', 'type']); export declare interface IonButtons extends Components.IonButtons {} +@ProxyCmp({inputs: ['collapse']}) @Component({ selector: 'ion-buttons', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['collapse'] }) export class IonButtons { protected el: HTMLElement; @@ -83,9 +86,9 @@ export class IonButtons { this.el = r.nativeElement; } } -proxyInputs(IonButtons, ['collapse']); export declare interface IonCard extends Components.IonCard {} +@ProxyCmp({inputs: ['button', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'target', 'type']}) @Component({ selector: 'ion-card', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['button', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'target', 'type'] }) export class IonCard { protected el: HTMLElement; @@ -94,9 +97,9 @@ export class IonCard { this.el = r.nativeElement; } } -proxyInputs(IonCard, ['button', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'target', 'type']); export declare interface IonCardContent extends Components.IonCardContent {} +@ProxyCmp({inputs: ['mode']}) @Component({ selector: 'ion-card-content', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['mode'] }) export class IonCardContent { protected el: HTMLElement; @@ -105,9 +108,9 @@ export class IonCardContent { this.el = r.nativeElement; } } -proxyInputs(IonCardContent, ['mode']); export declare interface IonCardHeader extends Components.IonCardHeader {} +@ProxyCmp({inputs: ['color', 'mode', 'translucent']}) @Component({ selector: 'ion-card-header', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode', 'translucent'] }) export class IonCardHeader { protected el: HTMLElement; @@ -116,9 +119,9 @@ export class IonCardHeader { this.el = r.nativeElement; } } -proxyInputs(IonCardHeader, ['color', 'mode', 'translucent']); export declare interface IonCardSubtitle extends Components.IonCardSubtitle {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-card-subtitle', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonCardSubtitle { protected el: HTMLElement; @@ -127,9 +130,9 @@ export class IonCardSubtitle { this.el = r.nativeElement; } } -proxyInputs(IonCardSubtitle, ['color', 'mode']); export declare interface IonCardTitle extends Components.IonCardTitle {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-card-title', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonCardTitle { protected el: HTMLElement; @@ -138,9 +141,9 @@ export class IonCardTitle { this.el = r.nativeElement; } } -proxyInputs(IonCardTitle, ['color', 'mode']); export declare interface IonCheckbox extends Components.IonCheckbox {} +@ProxyCmp({inputs: ['checked', 'color', 'disabled', 'indeterminate', 'mode', 'name', 'value']}) @Component({ selector: 'ion-checkbox', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['checked', 'color', 'disabled', 'indeterminate', 'mode', 'name', 'value'] }) export class IonCheckbox { ionChange!: EventEmitter; @@ -153,9 +156,9 @@ export class IonCheckbox { proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } } -proxyInputs(IonCheckbox, ['checked', 'color', 'disabled', 'indeterminate', 'mode', 'name', 'value']); export declare interface IonChip extends Components.IonChip {} +@ProxyCmp({inputs: ['color', 'mode', 'outline']}) @Component({ selector: 'ion-chip', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode', 'outline'] }) export class IonChip { protected el: HTMLElement; @@ -164,9 +167,9 @@ export class IonChip { this.el = r.nativeElement; } } -proxyInputs(IonChip, ['color', 'mode', 'outline']); export declare interface IonCol extends Components.IonCol {} +@ProxyCmp({inputs: ['offset', 'offsetLg', 'offsetMd', 'offsetSm', 'offsetXl', 'offsetXs', 'pull', 'pullLg', 'pullMd', 'pullSm', 'pullXl', 'pullXs', 'push', 'pushLg', 'pushMd', 'pushSm', 'pushXl', 'pushXs', 'size', 'sizeLg', 'sizeMd', 'sizeSm', 'sizeXl', 'sizeXs']}) @Component({ selector: 'ion-col', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['offset', 'offsetLg', 'offsetMd', 'offsetSm', 'offsetXl', 'offsetXs', 'pull', 'pullLg', 'pullMd', 'pullSm', 'pullXl', 'pullXs', 'push', 'pushLg', 'pushMd', 'pushSm', 'pushXl', 'pushXs', 'size', 'sizeLg', 'sizeMd', 'sizeSm', 'sizeXl', 'sizeXs'] }) export class IonCol { protected el: HTMLElement; @@ -175,9 +178,9 @@ export class IonCol { this.el = r.nativeElement; } } -proxyInputs(IonCol, ['offset', 'offsetLg', 'offsetMd', 'offsetSm', 'offsetXl', 'offsetXs', 'pull', 'pullLg', 'pullMd', 'pullSm', 'pullXl', 'pullXs', 'push', 'pushLg', 'pushMd', 'pushSm', 'pushXl', 'pushXs', 'size', 'sizeLg', 'sizeMd', 'sizeSm', 'sizeXl', 'sizeXs']); export declare interface IonContent extends Components.IonContent {} +@ProxyCmp({inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'], 'methods': ['getScrollElement', 'scrollToTop', 'scrollToBottom', 'scrollByPoint', 'scrollToPoint']}) @Component({ selector: 'ion-content', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'] }) export class IonContent { ionScrollStart!: EventEmitter; @@ -190,10 +193,9 @@ export class IonContent { proxyOutputs(this, this.el, ['ionScrollStart', 'ionScroll', 'ionScrollEnd']); } } -proxyMethods(IonContent, ['getScrollElement', 'scrollToTop', 'scrollToBottom', 'scrollByPoint', 'scrollToPoint']); -proxyInputs(IonContent, ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY']); export declare interface IonDatetime extends Components.IonDatetime {} +@ProxyCmp({inputs: ['cancelText', 'dayNames', 'dayShortNames', 'dayValues', 'disabled', 'displayFormat', 'doneText', 'hourValues', 'max', 'min', 'minuteValues', 'mode', 'monthNames', 'monthShortNames', 'monthValues', 'name', 'pickerFormat', 'pickerOptions', 'placeholder', 'readonly', 'value', 'yearValues'], 'methods': ['open']}) @Component({ selector: 'ion-datetime', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['cancelText', 'dayNames', 'dayShortNames', 'dayValues', 'disabled', 'displayFormat', 'doneText', 'hourValues', 'max', 'min', 'minuteValues', 'mode', 'monthNames', 'monthShortNames', 'monthValues', 'name', 'pickerFormat', 'pickerOptions', 'placeholder', 'readonly', 'value', 'yearValues'] }) export class IonDatetime { ionCancel!: EventEmitter; @@ -207,10 +209,9 @@ export class IonDatetime { proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']); } } -proxyMethods(IonDatetime, ['open']); -proxyInputs(IonDatetime, ['cancelText', 'dayNames', 'dayShortNames', 'dayValues', 'disabled', 'displayFormat', 'doneText', 'hourValues', 'max', 'min', 'minuteValues', 'mode', 'monthNames', 'monthShortNames', 'monthValues', 'name', 'pickerFormat', 'pickerOptions', 'placeholder', 'readonly', 'value', 'yearValues']); export declare interface IonFab extends Components.IonFab {} +@ProxyCmp({inputs: ['activated', 'edge', 'horizontal', 'vertical'], 'methods': ['close']}) @Component({ selector: 'ion-fab', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['activated', 'edge', 'horizontal', 'vertical'] }) export class IonFab { protected el: HTMLElement; @@ -219,10 +220,9 @@ export class IonFab { this.el = r.nativeElement; } } -proxyMethods(IonFab, ['close']); -proxyInputs(IonFab, ['activated', 'edge', 'horizontal', 'vertical']); export declare interface IonFabButton extends Components.IonFabButton {} +@ProxyCmp({inputs: ['activated', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'show', 'size', 'target', 'translucent', 'type']}) @Component({ selector: 'ion-fab-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['activated', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'show', 'size', 'target', 'translucent', 'type'] }) export class IonFabButton { ionFocus!: EventEmitter; @@ -234,9 +234,9 @@ export class IonFabButton { proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']); } } -proxyInputs(IonFabButton, ['activated', 'color', 'disabled', 'download', 'href', 'mode', 'rel', 'routerDirection', 'show', 'size', 'target', 'translucent', 'type']); export declare interface IonFabList extends Components.IonFabList {} +@ProxyCmp({inputs: ['activated', 'side']}) @Component({ selector: 'ion-fab-list', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['activated', 'side'] }) export class IonFabList { protected el: HTMLElement; @@ -245,9 +245,9 @@ export class IonFabList { this.el = r.nativeElement; } } -proxyInputs(IonFabList, ['activated', 'side']); export declare interface IonFooter extends Components.IonFooter {} +@ProxyCmp({inputs: ['mode', 'translucent']}) @Component({ selector: 'ion-footer', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['mode', 'translucent'] }) export class IonFooter { protected el: HTMLElement; @@ -256,9 +256,9 @@ export class IonFooter { this.el = r.nativeElement; } } -proxyInputs(IonFooter, ['mode', 'translucent']); export declare interface IonGrid extends Components.IonGrid {} +@ProxyCmp({inputs: ['fixed']}) @Component({ selector: 'ion-grid', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['fixed'] }) export class IonGrid { protected el: HTMLElement; @@ -267,9 +267,9 @@ export class IonGrid { this.el = r.nativeElement; } } -proxyInputs(IonGrid, ['fixed']); export declare interface IonHeader extends Components.IonHeader {} +@ProxyCmp({inputs: ['collapse', 'mode', 'translucent']}) @Component({ selector: 'ion-header', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['collapse', 'mode', 'translucent'] }) export class IonHeader { protected el: HTMLElement; @@ -278,9 +278,9 @@ export class IonHeader { this.el = r.nativeElement; } } -proxyInputs(IonHeader, ['collapse', 'mode', 'translucent']); export declare interface IonIcon extends Components.IonIcon {} +@ProxyCmp({inputs: ['ariaLabel', 'color', 'flipRtl', 'icon', 'ios', 'lazy', 'md', 'mode', 'name', 'size', 'src']}) @Component({ selector: 'ion-icon', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['ariaLabel', 'color', 'flipRtl', 'icon', 'ios', 'lazy', 'md', 'mode', 'name', 'size', 'src'] }) export class IonIcon { protected el: HTMLElement; @@ -289,9 +289,9 @@ export class IonIcon { this.el = r.nativeElement; } } -proxyInputs(IonIcon, ['ariaLabel', 'color', 'flipRtl', 'icon', 'ios', 'lazy', 'md', 'mode', 'name', 'size', 'src']); export declare interface IonImg extends Components.IonImg {} +@ProxyCmp({inputs: ['alt', 'src']}) @Component({ selector: 'ion-img', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['alt', 'src'] }) export class IonImg { ionImgWillLoad!: EventEmitter; @@ -304,9 +304,9 @@ export class IonImg { proxyOutputs(this, this.el, ['ionImgWillLoad', 'ionImgDidLoad', 'ionError']); } } -proxyInputs(IonImg, ['alt', 'src']); export declare interface IonInfiniteScroll extends Components.IonInfiniteScroll {} +@ProxyCmp({inputs: ['disabled', 'position', 'threshold'], 'methods': ['complete']}) @Component({ selector: 'ion-infinite-scroll', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['disabled', 'position', 'threshold'] }) export class IonInfiniteScroll { ionInfinite!: EventEmitter; @@ -317,10 +317,9 @@ export class IonInfiniteScroll { proxyOutputs(this, this.el, ['ionInfinite']); } } -proxyMethods(IonInfiniteScroll, ['complete']); -proxyInputs(IonInfiniteScroll, ['disabled', 'position', 'threshold']); export declare interface IonInfiniteScrollContent extends Components.IonInfiniteScrollContent {} +@ProxyCmp({inputs: ['loadingSpinner', 'loadingText']}) @Component({ selector: 'ion-infinite-scroll-content', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['loadingSpinner', 'loadingText'] }) export class IonInfiniteScrollContent { protected el: HTMLElement; @@ -329,9 +328,9 @@ export class IonInfiniteScrollContent { this.el = r.nativeElement; } } -proxyInputs(IonInfiniteScrollContent, ['loadingSpinner', 'loadingText']); export declare interface IonInput extends Components.IonInput {} +@ProxyCmp({inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'debounce', 'disabled', 'inputmode', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'size', 'spellcheck', 'step', 'type', 'value'], 'methods': ['setFocus', 'getInputElement']}) @Component({ selector: 'ion-input', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'debounce', 'disabled', 'inputmode', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'size', 'spellcheck', 'step', 'type', 'value'] }) export class IonInput { ionInput!: EventEmitter; @@ -345,10 +344,9 @@ export class IonInput { proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionBlur', 'ionFocus']); } } -proxyMethods(IonInput, ['setFocus', 'getInputElement']); -proxyInputs(IonInput, ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'debounce', 'disabled', 'inputmode', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'size', 'spellcheck', 'step', 'type', 'value']); export declare interface IonItem extends Components.IonItem {} +@ProxyCmp({inputs: ['button', 'color', 'detail', 'detailIcon', 'disabled', 'download', 'href', 'lines', 'mode', 'rel', 'routerDirection', 'target', 'type']}) @Component({ selector: 'ion-item', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['button', 'color', 'detail', 'detailIcon', 'disabled', 'download', 'href', 'lines', 'mode', 'rel', 'routerDirection', 'target', 'type'] }) export class IonItem { protected el: HTMLElement; @@ -357,9 +355,9 @@ export class IonItem { this.el = r.nativeElement; } } -proxyInputs(IonItem, ['button', 'color', 'detail', 'detailIcon', 'disabled', 'download', 'href', 'lines', 'mode', 'rel', 'routerDirection', 'target', 'type']); export declare interface IonItemDivider extends Components.IonItemDivider {} +@ProxyCmp({inputs: ['color', 'mode', 'sticky']}) @Component({ selector: 'ion-item-divider', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode', 'sticky'] }) export class IonItemDivider { protected el: HTMLElement; @@ -368,9 +366,9 @@ export class IonItemDivider { this.el = r.nativeElement; } } -proxyInputs(IonItemDivider, ['color', 'mode', 'sticky']); export declare interface IonItemGroup extends Components.IonItemGroup {} + @Component({ selector: 'ion-item-group', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonItemGroup { protected el: HTMLElement; @@ -381,6 +379,7 @@ export class IonItemGroup { } export declare interface IonItemOption extends Components.IonItemOption {} +@ProxyCmp({inputs: ['color', 'disabled', 'download', 'expandable', 'href', 'mode', 'rel', 'target', 'type']}) @Component({ selector: 'ion-item-option', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'disabled', 'download', 'expandable', 'href', 'mode', 'rel', 'target', 'type'] }) export class IonItemOption { protected el: HTMLElement; @@ -389,9 +388,9 @@ export class IonItemOption { this.el = r.nativeElement; } } -proxyInputs(IonItemOption, ['color', 'disabled', 'download', 'expandable', 'href', 'mode', 'rel', 'target', 'type']); export declare interface IonItemOptions extends Components.IonItemOptions {} +@ProxyCmp({inputs: ['side']}) @Component({ selector: 'ion-item-options', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['side'] }) export class IonItemOptions { ionSwipe!: EventEmitter; @@ -402,9 +401,9 @@ export class IonItemOptions { proxyOutputs(this, this.el, ['ionSwipe']); } } -proxyInputs(IonItemOptions, ['side']); export declare interface IonItemSliding extends Components.IonItemSliding {} +@ProxyCmp({inputs: ['disabled'], 'methods': ['getOpenAmount', 'getSlidingRatio', 'open', 'close', 'closeOpened']}) @Component({ selector: 'ion-item-sliding', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['disabled'] }) export class IonItemSliding { ionDrag!: EventEmitter; @@ -415,10 +414,9 @@ export class IonItemSliding { proxyOutputs(this, this.el, ['ionDrag']); } } -proxyMethods(IonItemSliding, ['getOpenAmount', 'getSlidingRatio', 'open', 'close', 'closeOpened']); -proxyInputs(IonItemSliding, ['disabled']); export declare interface IonLabel extends Components.IonLabel {} +@ProxyCmp({inputs: ['color', 'mode', 'position']}) @Component({ selector: 'ion-label', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode', 'position'] }) export class IonLabel { protected el: HTMLElement; @@ -427,9 +425,9 @@ export class IonLabel { this.el = r.nativeElement; } } -proxyInputs(IonLabel, ['color', 'mode', 'position']); export declare interface IonList extends Components.IonList {} +@ProxyCmp({inputs: ['inset', 'lines', 'mode'], 'methods': ['closeSlidingItems']}) @Component({ selector: 'ion-list', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['inset', 'lines', 'mode'] }) export class IonList { protected el: HTMLElement; @@ -438,10 +436,9 @@ export class IonList { this.el = r.nativeElement; } } -proxyMethods(IonList, ['closeSlidingItems']); -proxyInputs(IonList, ['inset', 'lines', 'mode']); export declare interface IonListHeader extends Components.IonListHeader {} +@ProxyCmp({inputs: ['color', 'lines', 'mode']}) @Component({ selector: 'ion-list-header', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'lines', 'mode'] }) export class IonListHeader { protected el: HTMLElement; @@ -450,9 +447,9 @@ export class IonListHeader { this.el = r.nativeElement; } } -proxyInputs(IonListHeader, ['color', 'lines', 'mode']); export declare interface IonMenu extends Components.IonMenu {} +@ProxyCmp({inputs: ['contentId', 'disabled', 'maxEdgeStart', 'menuId', 'side', 'swipeGesture', 'type'], 'methods': ['isOpen', 'isActive', 'open', 'close', 'toggle', 'setOpen']}) @Component({ selector: 'ion-menu', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['contentId', 'disabled', 'maxEdgeStart', 'menuId', 'side', 'swipeGesture', 'type'] }) export class IonMenu { ionWillOpen!: EventEmitter; @@ -466,10 +463,9 @@ export class IonMenu { proxyOutputs(this, this.el, ['ionWillOpen', 'ionWillClose', 'ionDidOpen', 'ionDidClose']); } } -proxyMethods(IonMenu, ['isOpen', 'isActive', 'open', 'close', 'toggle', 'setOpen']); -proxyInputs(IonMenu, ['contentId', 'disabled', 'maxEdgeStart', 'menuId', 'side', 'swipeGesture', 'type']); export declare interface IonMenuButton extends Components.IonMenuButton {} +@ProxyCmp({inputs: ['autoHide', 'color', 'disabled', 'menu', 'type']}) @Component({ selector: 'ion-menu-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['autoHide', 'color', 'disabled', 'menu', 'type'] }) export class IonMenuButton { protected el: HTMLElement; @@ -478,9 +474,9 @@ export class IonMenuButton { this.el = r.nativeElement; } } -proxyInputs(IonMenuButton, ['autoHide', 'color', 'disabled', 'menu', 'type']); export declare interface IonMenuToggle extends Components.IonMenuToggle {} +@ProxyCmp({inputs: ['autoHide', 'menu']}) @Component({ selector: 'ion-menu-toggle', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['autoHide', 'menu'] }) export class IonMenuToggle { protected el: HTMLElement; @@ -489,9 +485,9 @@ export class IonMenuToggle { this.el = r.nativeElement; } } -proxyInputs(IonMenuToggle, ['autoHide', 'menu']); export declare interface IonNav extends Components.IonNav {} +@ProxyCmp({inputs: ['animated', 'animation', 'root', 'rootParams', 'swipeGesture'], 'methods': ['push', 'insert', 'insertPages', 'pop', 'popTo', 'popToRoot', 'removeIndex', 'setRoot', 'setPages', 'getActive', 'getByIndex', 'canGoBack', 'getPrevious']}) @Component({ selector: 'ion-nav', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['animated', 'animation', 'root', 'rootParams', 'swipeGesture'] }) export class IonNav { ionNavWillChange!: EventEmitter; @@ -503,10 +499,9 @@ export class IonNav { proxyOutputs(this, this.el, ['ionNavWillChange', 'ionNavDidChange']); } } -proxyMethods(IonNav, ['push', 'insert', 'insertPages', 'pop', 'popTo', 'popToRoot', 'removeIndex', 'setRoot', 'setPages', 'getActive', 'getByIndex', 'canGoBack', 'getPrevious']); -proxyInputs(IonNav, ['animated', 'animation', 'root', 'rootParams', 'swipeGesture']); export declare interface IonNavLink extends Components.IonNavLink {} +@ProxyCmp({inputs: ['component', 'componentProps', 'routerDirection']}) @Component({ selector: 'ion-nav-link', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['component', 'componentProps', 'routerDirection'] }) export class IonNavLink { protected el: HTMLElement; @@ -515,9 +510,9 @@ export class IonNavLink { this.el = r.nativeElement; } } -proxyInputs(IonNavLink, ['component', 'componentProps', 'routerDirection']); export declare interface IonNote extends Components.IonNote {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-note', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonNote { protected el: HTMLElement; @@ -526,9 +521,9 @@ export class IonNote { this.el = r.nativeElement; } } -proxyInputs(IonNote, ['color', 'mode']); export declare interface IonProgressBar extends Components.IonProgressBar {} +@ProxyCmp({inputs: ['buffer', 'color', 'mode', 'reversed', 'type', 'value']}) @Component({ selector: 'ion-progress-bar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['buffer', 'color', 'mode', 'reversed', 'type', 'value'] }) export class IonProgressBar { protected el: HTMLElement; @@ -537,9 +532,9 @@ export class IonProgressBar { this.el = r.nativeElement; } } -proxyInputs(IonProgressBar, ['buffer', 'color', 'mode', 'reversed', 'type', 'value']); export declare interface IonRadio extends Components.IonRadio {} +@ProxyCmp({inputs: ['checked', 'color', 'disabled', 'mode', 'name', 'value']}) @Component({ selector: 'ion-radio', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['checked', 'color', 'disabled', 'mode', 'name', 'value'] }) export class IonRadio { ionSelect!: EventEmitter; @@ -552,9 +547,9 @@ export class IonRadio { proxyOutputs(this, this.el, ['ionSelect', 'ionFocus', 'ionBlur']); } } -proxyInputs(IonRadio, ['checked', 'color', 'disabled', 'mode', 'name', 'value']); export declare interface IonRadioGroup extends Components.IonRadioGroup {} +@ProxyCmp({inputs: ['allowEmptySelection', 'name', 'value']}) @Component({ selector: 'ion-radio-group', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['allowEmptySelection', 'name', 'value'] }) export class IonRadioGroup { ionChange!: EventEmitter; @@ -565,9 +560,9 @@ export class IonRadioGroup { proxyOutputs(this, this.el, ['ionChange']); } } -proxyInputs(IonRadioGroup, ['allowEmptySelection', 'name', 'value']); export declare interface IonRange extends Components.IonRange {} +@ProxyCmp({inputs: ['color', 'debounce', 'disabled', 'dualKnobs', 'max', 'min', 'mode', 'name', 'pin', 'snaps', 'step', 'ticks', 'value']}) @Component({ selector: 'ion-range', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'debounce', 'disabled', 'dualKnobs', 'max', 'min', 'mode', 'name', 'pin', 'snaps', 'step', 'ticks', 'value'] }) export class IonRange { ionChange!: EventEmitter; @@ -580,9 +575,9 @@ export class IonRange { proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } } -proxyInputs(IonRange, ['color', 'debounce', 'disabled', 'dualKnobs', 'max', 'min', 'mode', 'name', 'pin', 'snaps', 'step', 'ticks', 'value']); export declare interface IonRefresher extends Components.IonRefresher {} +@ProxyCmp({inputs: ['closeDuration', 'disabled', 'pullFactor', 'pullMax', 'pullMin', 'snapbackDuration'], 'methods': ['complete', 'cancel', 'getProgress']}) @Component({ selector: 'ion-refresher', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['closeDuration', 'disabled', 'pullFactor', 'pullMax', 'pullMin', 'snapbackDuration'] }) export class IonRefresher { ionRefresh!: EventEmitter; @@ -595,10 +590,9 @@ export class IonRefresher { proxyOutputs(this, this.el, ['ionRefresh', 'ionPull', 'ionStart']); } } -proxyMethods(IonRefresher, ['complete', 'cancel', 'getProgress']); -proxyInputs(IonRefresher, ['closeDuration', 'disabled', 'pullFactor', 'pullMax', 'pullMin', 'snapbackDuration']); export declare interface IonRefresherContent extends Components.IonRefresherContent {} +@ProxyCmp({inputs: ['pullingIcon', 'pullingText', 'refreshingSpinner', 'refreshingText']}) @Component({ selector: 'ion-refresher-content', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['pullingIcon', 'pullingText', 'refreshingSpinner', 'refreshingText'] }) export class IonRefresherContent { protected el: HTMLElement; @@ -607,9 +601,9 @@ export class IonRefresherContent { this.el = r.nativeElement; } } -proxyInputs(IonRefresherContent, ['pullingIcon', 'pullingText', 'refreshingSpinner', 'refreshingText']); export declare interface IonReorder extends Components.IonReorder {} + @Component({ selector: 'ion-reorder', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonReorder { protected el: HTMLElement; @@ -620,6 +614,7 @@ export class IonReorder { } export declare interface IonReorderGroup extends Components.IonReorderGroup {} +@ProxyCmp({inputs: ['disabled'], 'methods': ['complete']}) @Component({ selector: 'ion-reorder-group', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['disabled'] }) export class IonReorderGroup { ionItemReorder!: EventEmitter; @@ -630,10 +625,9 @@ export class IonReorderGroup { proxyOutputs(this, this.el, ['ionItemReorder']); } } -proxyMethods(IonReorderGroup, ['complete']); -proxyInputs(IonReorderGroup, ['disabled']); export declare interface IonRippleEffect extends Components.IonRippleEffect {} +@ProxyCmp({inputs: ['type'], 'methods': ['addRipple']}) @Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['type'] }) export class IonRippleEffect { protected el: HTMLElement; @@ -642,10 +636,9 @@ export class IonRippleEffect { this.el = r.nativeElement; } } -proxyMethods(IonRippleEffect, ['addRipple']); -proxyInputs(IonRippleEffect, ['type']); export declare interface IonRow extends Components.IonRow {} + @Component({ selector: 'ion-row', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonRow { protected el: HTMLElement; @@ -656,6 +649,7 @@ export class IonRow { } export declare interface IonSearchbar extends Components.IonSearchbar {} +@ProxyCmp({inputs: ['animated', 'autocomplete', 'autocorrect', 'cancelButtonIcon', 'cancelButtonText', 'clearIcon', 'color', 'debounce', 'disabled', 'inputmode', 'mode', 'placeholder', 'searchIcon', 'showCancelButton', 'spellcheck', 'type', 'value'], 'methods': ['setFocus', 'getInputElement']}) @Component({ selector: 'ion-searchbar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['animated', 'autocomplete', 'autocorrect', 'cancelButtonIcon', 'cancelButtonText', 'clearIcon', 'color', 'debounce', 'disabled', 'inputmode', 'mode', 'placeholder', 'searchIcon', 'showCancelButton', 'spellcheck', 'type', 'value'] }) export class IonSearchbar { ionInput!: EventEmitter; @@ -671,10 +665,9 @@ export class IonSearchbar { proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus']); } } -proxyMethods(IonSearchbar, ['setFocus', 'getInputElement']); -proxyInputs(IonSearchbar, ['animated', 'autocomplete', 'autocorrect', 'cancelButtonIcon', 'cancelButtonText', 'clearIcon', 'color', 'debounce', 'disabled', 'inputmode', 'mode', 'placeholder', 'searchIcon', 'showCancelButton', 'spellcheck', 'type', 'value']); export declare interface IonSegment extends Components.IonSegment {} +@ProxyCmp({inputs: ['color', 'disabled', 'mode', 'scrollable', 'value']}) @Component({ selector: 'ion-segment', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'disabled', 'mode', 'scrollable', 'value'] }) export class IonSegment { ionChange!: EventEmitter; @@ -685,9 +678,9 @@ export class IonSegment { proxyOutputs(this, this.el, ['ionChange']); } } -proxyInputs(IonSegment, ['color', 'disabled', 'mode', 'scrollable', 'value']); export declare interface IonSegmentButton extends Components.IonSegmentButton {} +@ProxyCmp({inputs: ['checked', 'disabled', 'layout', 'mode', 'type', 'value']}) @Component({ selector: 'ion-segment-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['checked', 'disabled', 'layout', 'mode', 'type', 'value'] }) export class IonSegmentButton { ionSelect!: EventEmitter; @@ -698,9 +691,9 @@ export class IonSegmentButton { proxyOutputs(this, this.el, ['ionSelect']); } } -proxyInputs(IonSegmentButton, ['checked', 'disabled', 'layout', 'mode', 'type', 'value']); export declare interface IonSelect extends Components.IonSelect {} +@ProxyCmp({inputs: ['cancelText', 'compareWith', 'disabled', 'interface', 'interfaceOptions', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'value'], 'methods': ['open']}) @Component({ selector: 'ion-select', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['cancelText', 'compareWith', 'disabled', 'interface', 'interfaceOptions', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'value'] }) export class IonSelect { ionChange!: EventEmitter; @@ -714,10 +707,9 @@ export class IonSelect { proxyOutputs(this, this.el, ['ionChange', 'ionCancel', 'ionFocus', 'ionBlur']); } } -proxyMethods(IonSelect, ['open']); -proxyInputs(IonSelect, ['cancelText', 'compareWith', 'disabled', 'interface', 'interfaceOptions', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'value']); export declare interface IonSelectOption extends Components.IonSelectOption {} +@ProxyCmp({inputs: ['disabled', 'selected', 'value']}) @Component({ selector: 'ion-select-option', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['disabled', 'selected', 'value'] }) export class IonSelectOption { protected el: HTMLElement; @@ -726,9 +718,9 @@ export class IonSelectOption { this.el = r.nativeElement; } } -proxyInputs(IonSelectOption, ['disabled', 'selected', 'value']); export declare interface IonSkeletonText extends Components.IonSkeletonText {} +@ProxyCmp({inputs: ['animated']}) @Component({ selector: 'ion-skeleton-text', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['animated'] }) export class IonSkeletonText { protected el: HTMLElement; @@ -737,9 +729,9 @@ export class IonSkeletonText { this.el = r.nativeElement; } } -proxyInputs(IonSkeletonText, ['animated']); export declare interface IonSlide extends Components.IonSlide {} + @Component({ selector: 'ion-slide', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonSlide { protected el: HTMLElement; @@ -750,6 +742,7 @@ export class IonSlide { } export declare interface IonSlides extends Components.IonSlides {} +@ProxyCmp({inputs: ['mode', 'options', 'pager', 'scrollbar'], 'methods': ['update', 'updateAutoHeight', 'slideTo', 'slideNext', 'slidePrev', 'getActiveIndex', 'getPreviousIndex', 'length', 'isEnd', 'isBeginning', 'startAutoplay', 'stopAutoplay', 'lockSwipeToNext', 'lockSwipeToPrev', 'lockSwipes', 'getSwiper']}) @Component({ selector: 'ion-slides', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['mode', 'options', 'pager', 'scrollbar'] }) export class IonSlides { ionSlidesDidLoad!: EventEmitter; @@ -775,10 +768,9 @@ export class IonSlides { proxyOutputs(this, this.el, ['ionSlidesDidLoad', 'ionSlideTap', 'ionSlideDoubleTap', 'ionSlideWillChange', 'ionSlideDidChange', 'ionSlideNextStart', 'ionSlidePrevStart', 'ionSlideNextEnd', 'ionSlidePrevEnd', 'ionSlideTransitionStart', 'ionSlideTransitionEnd', 'ionSlideDrag', 'ionSlideReachStart', 'ionSlideReachEnd', 'ionSlideTouchStart', 'ionSlideTouchEnd']); } } -proxyMethods(IonSlides, ['update', 'updateAutoHeight', 'slideTo', 'slideNext', 'slidePrev', 'getActiveIndex', 'getPreviousIndex', 'length', 'isEnd', 'isBeginning', 'startAutoplay', 'stopAutoplay', 'lockSwipeToNext', 'lockSwipeToPrev', 'lockSwipes', 'getSwiper']); -proxyInputs(IonSlides, ['mode', 'options', 'pager', 'scrollbar']); export declare interface IonSpinner extends Components.IonSpinner {} +@ProxyCmp({inputs: ['color', 'duration', 'name', 'paused']}) @Component({ selector: 'ion-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'duration', 'name', 'paused'] }) export class IonSpinner { protected el: HTMLElement; @@ -787,9 +779,9 @@ export class IonSpinner { this.el = r.nativeElement; } } -proxyInputs(IonSpinner, ['color', 'duration', 'name', 'paused']); export declare interface IonSplitPane extends Components.IonSplitPane {} +@ProxyCmp({inputs: ['contentId', 'disabled', 'when']}) @Component({ selector: 'ion-split-pane', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['contentId', 'disabled', 'when'] }) export class IonSplitPane { ionSplitPaneVisible!: EventEmitter; @@ -800,9 +792,9 @@ export class IonSplitPane { proxyOutputs(this, this.el, ['ionSplitPaneVisible']); } } -proxyInputs(IonSplitPane, ['contentId', 'disabled', 'when']); export declare interface IonTabBar extends Components.IonTabBar {} +@ProxyCmp({inputs: ['color', 'mode', 'selectedTab', 'translucent']}) @Component({ selector: 'ion-tab-bar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode', 'selectedTab', 'translucent'] }) export class IonTabBar { protected el: HTMLElement; @@ -811,9 +803,9 @@ export class IonTabBar { this.el = r.nativeElement; } } -proxyInputs(IonTabBar, ['color', 'mode', 'selectedTab', 'translucent']); export declare interface IonTabButton extends Components.IonTabButton {} +@ProxyCmp({inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target']}) @Component({ selector: 'ion-tab-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target'] }) export class IonTabButton { protected el: HTMLElement; @@ -822,9 +814,9 @@ export class IonTabButton { this.el = r.nativeElement; } } -proxyInputs(IonTabButton, ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target']); export declare interface IonText extends Components.IonText {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-text', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonText { protected el: HTMLElement; @@ -833,9 +825,9 @@ export class IonText { this.el = r.nativeElement; } } -proxyInputs(IonText, ['color', 'mode']); export declare interface IonTextarea extends Components.IonTextarea {} +@ProxyCmp({inputs: ['autoGrow', 'autocapitalize', 'autofocus', 'clearOnEdit', 'color', 'cols', 'debounce', 'disabled', 'maxlength', 'minlength', 'mode', 'name', 'placeholder', 'readonly', 'required', 'rows', 'spellcheck', 'value', 'wrap'], 'methods': ['setFocus', 'getInputElement']}) @Component({ selector: 'ion-textarea', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['autoGrow', 'autocapitalize', 'autofocus', 'clearOnEdit', 'color', 'cols', 'debounce', 'disabled', 'maxlength', 'minlength', 'mode', 'name', 'placeholder', 'readonly', 'required', 'rows', 'spellcheck', 'value', 'wrap'] }) export class IonTextarea { ionChange!: EventEmitter; @@ -849,10 +841,9 @@ export class IonTextarea { proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionBlur', 'ionFocus']); } } -proxyMethods(IonTextarea, ['setFocus', 'getInputElement']); -proxyInputs(IonTextarea, ['autoGrow', 'autocapitalize', 'autofocus', 'clearOnEdit', 'color', 'cols', 'debounce', 'disabled', 'maxlength', 'minlength', 'mode', 'name', 'placeholder', 'readonly', 'required', 'rows', 'spellcheck', 'value', 'wrap']); export declare interface IonThumbnail extends Components.IonThumbnail {} + @Component({ selector: 'ion-thumbnail', changeDetection: ChangeDetectionStrategy.OnPush, template: '' }) export class IonThumbnail { protected el: HTMLElement; @@ -863,6 +854,7 @@ export class IonThumbnail { } export declare interface IonTitle extends Components.IonTitle {} +@ProxyCmp({inputs: ['color', 'size']}) @Component({ selector: 'ion-title', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'size'] }) export class IonTitle { protected el: HTMLElement; @@ -871,9 +863,9 @@ export class IonTitle { this.el = r.nativeElement; } } -proxyInputs(IonTitle, ['color', 'size']); export declare interface IonToggle extends Components.IonToggle {} +@ProxyCmp({inputs: ['checked', 'color', 'disabled', 'mode', 'name', 'value']}) @Component({ selector: 'ion-toggle', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['checked', 'color', 'disabled', 'mode', 'name', 'value'] }) export class IonToggle { ionChange!: EventEmitter; @@ -886,9 +878,9 @@ export class IonToggle { proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } } -proxyInputs(IonToggle, ['checked', 'color', 'disabled', 'mode', 'name', 'value']); export declare interface IonToolbar extends Components.IonToolbar {} +@ProxyCmp({inputs: ['color', 'mode']}) @Component({ selector: 'ion-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', inputs: ['color', 'mode'] }) export class IonToolbar { protected el: HTMLElement; @@ -897,4 +889,3 @@ export class IonToolbar { this.el = r.nativeElement; } } -proxyInputs(IonToolbar, ['color', 'mode']); diff --git a/angular/src/directives/virtual-scroll/virtual-scroll.ts b/angular/src/directives/virtual-scroll/virtual-scroll.ts index f0f235dde1..b28f55bd76 100644 --- a/angular/src/directives/virtual-scroll/virtual-scroll.ts +++ b/angular/src/directives/virtual-scroll/virtual-scroll.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EmbeddedViewRef, IterableDiffer, IterableDiffers, NgZone, SimpleChanges, TrackByFunction } from '@angular/core'; import { Cell, CellType, FooterHeightFn, HeaderFn, HeaderHeightFn, ItemHeightFn } from '@ionic/core'; -import { proxyInputs, proxyMethods } from '../proxies-utils'; +import { ProxyCmp } from '../proxies-utils'; import { VirtualFooter } from './virtual-footer'; import { VirtualHeader } from './virtual-header'; @@ -112,6 +112,10 @@ export declare interface IonVirtualScroll { 'positionForItem': (index: number) => Promise; } +@ProxyCmp({ + inputs: ['approxItemHeight', 'approxHeaderHeight', 'approxFooterHeight', 'headerFn', 'footerFn', 'items', 'itemHeight', 'headerHeight', 'footerHeight'], + methods: ['checkEnd', 'checkRange', 'positionForItem'] +}) @Component({ selector: 'ion-virtual-scroll', template: '', @@ -133,11 +137,11 @@ export class IonVirtualScroll { private differ?: IterableDiffer; private el: HTMLIonVirtualScrollElement; - private refMap = new WeakMap> (); + private refMap = new WeakMap>(); - @ContentChild(VirtualItem) itmTmp!: VirtualItem; - @ContentChild(VirtualHeader) hdrTmp!: VirtualHeader; - @ContentChild(VirtualFooter) ftrTmp!: VirtualFooter; + @ContentChild(VirtualItem, { static: false }) itmTmp!: VirtualItem; + @ContentChild(VirtualHeader, { static: false }) hdrTmp!: VirtualHeader; + @ContentChild(VirtualFooter, { static: false }) ftrTmp!: VirtualFooter; constructor( private z: NgZone, @@ -215,21 +219,3 @@ const getElement = (view: EmbeddedViewRef): HTMLElement => { } throw new Error('virtual element was not created'); }; - -proxyInputs(IonVirtualScroll, [ - 'approxItemHeight', - 'approxHeaderHeight', - 'approxFooterHeight', - 'headerFn', - 'footerFn', - 'items', - 'itemHeight', - 'headerHeight', - 'footerHeight' -]); - -proxyMethods(IonVirtualScroll, [ - 'checkEnd', - 'checkRange', - 'positionForItem' -]); diff --git a/angular/src/ionic-module.ts b/angular/src/ionic-module.ts index 04d1fd4eae..a3ea4a8fb7 100644 --- a/angular/src/ionic-module.ts +++ b/angular/src/ionic-module.ts @@ -126,7 +126,7 @@ const DECLARATIONS = [ imports: [CommonModule] }) export class IonicModule { - static forRoot(config?: IonicConfig): ModuleWithProviders { + static forRoot(config?: IonicConfig): ModuleWithProviders { return { ngModule: IonicModule, providers: [ diff --git a/angular/test/test-app/angular.json b/angular/test/test-app/angular.json index 02b0705563..edf436e66c 100644 --- a/angular/test/test-app/angular.json +++ b/angular/test/test-app/angular.json @@ -13,11 +13,13 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { - "outputPath": "dist/browser", + "aot": true, + "outputPath": "dist/test-app/browser", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", + "buildOptimizer": true, "assets": [ "src/favicon.ico", { @@ -57,6 +59,10 @@ "type": "initial", "maximumWarning": "2mb", "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" } ] } @@ -116,20 +122,44 @@ "server": { "builder": "@angular-devkit/build-angular:server", "options": { - "outputPath": "dist/server", - "main": "src/main.server.ts", + "outputPath": "dist/test-app/server", + "main": "server.ts", "tsConfig": "tsconfig.server.json" }, "configurations": { "production": { + "outputHashing": "media", "fileReplacements": [ { - "src": "src/environments/environment.ts", - "replaceWith": "src/environments/environment.prod.ts" + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" } - ] + ], + "sourceMap": false, + "optimization": true } } + }, + "serve-ssr": { + "builder": "@nguniversal/builders:ssr-dev-server", + "options": { + "browserTarget": "test-app:build", + "serverTarget": "test-app:server" + }, + "configurations": { + "production": { + "browserTarget": "test-app:build:production", + "serverTarget": "test-app:server:production" + } + } + }, + "prerender": { + "builder": "@nguniversal/builders:prerender", + "options": { + "browserTarget": "test-app:build:production", + "serverTarget": "test-app:server:production", + "routes": [] + } } } } diff --git a/angular/test/test-app/e2e/protractor.conf.js b/angular/test/test-app/e2e/protractor.conf.js index 7e68f9da19..afc1ec00d6 100644 --- a/angular/test/test-app/e2e/protractor.conf.js +++ b/angular/test/test-app/e2e/protractor.conf.js @@ -1,4 +1,4 @@ - // @ts-check +// @ts-check // Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts @@ -23,7 +23,7 @@ exports.config = { framework: 'jasmine', jasmineNodeOpts: { showColors: true, - defaultTimeoutInterval: 70000, + defaultTimeoutInterval: 100000, print: function() {} }, onPrepare() { diff --git a/angular/test/test-app/karma.conf.js b/angular/test/test-app/karma.conf.js index 0c016e5643..af072fc954 100644 --- a/angular/test/test-app/karma.conf.js +++ b/angular/test/test-app/karma.conf.js @@ -8,6 +8,8 @@ module.exports = function (config) { plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma') ], client: { @@ -24,6 +26,7 @@ module.exports = function (config) { logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], - singleRun: false + singleRun: false, + restartOnFileChange: true }); -}; \ No newline at end of file +}; diff --git a/angular/test/test-app/package.json b/angular/test/test-app/package.json index 2ee5224e4a..84c79db167 100644 --- a/angular/test/test-app/package.json +++ b/angular/test/test-app/package.json @@ -11,50 +11,53 @@ "test": "ng e2e --prod", "test.dev": "npm run sync && ng e2e", "lint": "ng lint", - "postinstall": "npm run sync", - "compile:server": "webpack --config webpack.server.config.js --progress --colors", - "serve:ssr": "node dist/server", - "build:ssr": "npm run build:client-and-server-bundles && npm run compile:server", - "build:client-and-server-bundles": "npm run build && ng run test-app:server:production --bundleDependencies all" + "postinstall": "npm run sync && ngcc", + "serve:ssr": "node dist/test-app/server/main.js", + "build:ssr": "ng build --prod && ng run test-app:server:production", + "dev:ssr": "ng run test-app:serve-ssr", + "prerender": "ng run test-app:prerender" }, "dependencies": { - "@angular/animations": "^8.2.8", - "@angular/common": "^8.2.8", - "@angular/compiler": "^8.2.8", - "@angular/core": "^8.2.8", - "@angular/forms": "^8.2.8", - "@angular/platform-browser": "^8.2.8", - "@angular/platform-browser-dynamic": "^8.2.8", - "@angular/platform-server": "^8.2.8", - "@angular/router": "^8.2.8", + "@angular/animations": "^9.0.0-rc.2", + "@angular/common": "^9.0.0-rc.2", + "@angular/compiler": "^9.0.0-rc.2", + "@angular/core": "^9.0.0-rc.2", + "@angular/forms": "^9.0.0-rc.2", + "@angular/platform-browser": "^9.0.0-rc.2", + "@angular/platform-browser-dynamic": "^9.0.0-rc.2", + "@angular/platform-server": "^9.0.0-rc.2", + "@angular/router": "^9.0.0-rc.2", "@ionic/angular": "^4.7.0", "@ionic/angular-server": "^0.0.2", - "@nguniversal/express-engine": "~8.1.1", - "@nguniversal/module-map-ngfactory-loader": "~8.1.1", + "@nguniversal/express-engine": "9.0.0-next.9", "core-js": "^2.6.2", "express": "^4.15.2", "rxjs": "^6.5.3", - "tslib": "^1.9.0", - "zone.js": "~0.9.1" + "tslib": "^1.10.0", + "zone.js": "~0.10.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^0.803.6", - "@angular/cli": "^8.3.6", - "@angular/compiler-cli": "^8.2.8", - "@angular/language-service": "^8.2.8", + "@angular-devkit/build-angular": "~0.900.0-rc.2", + "@angular/cli": "^9.0.0-rc.2", + "@angular/compiler-cli": "^9.0.0-rc.2", + "@angular/language-service": "^9.0.0-rc.2", + "@nguniversal/builders": "^9.0.0-next.9", + "@types/express": "^4.17.0", "@types/jasmine": "3.4.1", - "@types/node": "12.7.8", + "@types/node": "^12.11.1", "codelyzer": "^5.1.2", - "jasmine-core": "3.5.0", - "jasmine-spec-reporter": "4.2.1", - "karma": "4.3.0", - "karma-chrome-launcher": "3.1.0", - "karma-jasmine": "2.0.1", - "protractor": "5.4.2", + "jasmine-core": "~3.5.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~2.1.0", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.4.2", + "protractor": "~5.4.2", "ts-loader": "^6.1.2", "ts-node": "8.4.1", "tslint": "~5.18.0", - "typescript": "~3.5.3", + "typescript": "~3.6.4", "webpack-cli": "^3.3.9" } } diff --git a/angular/test/test-app/scripts/sync.sh b/angular/test/test-app/scripts/sync.sh index 026bb5f2ee..c71695a723 100644 --- a/angular/test/test-app/scripts/sync.sh +++ b/angular/test/test-app/scripts/sync.sh @@ -1,15 +1,10 @@ # Copy angular dist rm -rf node_modules/@ionic/angular -mkdir node_modules/@ionic/angular -cp -a ../../dist node_modules/@ionic/angular/dist -cp -a ../../css node_modules/@ionic/angular/css -cp -a ../../package.json node_modules/@ionic/angular/package.json +cp -a ../../dist node_modules/@ionic/angular # Copy angular server rm -rf node_modules/@ionic/angular-server -mkdir node_modules/@ionic/angular-server -cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server/dist -cp -a ../../../packages/angular-server/package.json node_modules/@ionic/angular-server/package.json +cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server # # Copy core dist rm -rf node_modules/@ionic/core diff --git a/angular/test/test-app/server.ts b/angular/test/test-app/server.ts index 4142104fd7..cbd3cd9efc 100644 --- a/angular/test/test-app/server.ts +++ b/angular/test/test-app/server.ts @@ -1,58 +1,57 @@ -/** - * *** NOTE ON IMPORTING FROM ANGULAR AND NGUNIVERSAL IN THIS FILE *** - * - * If your application uses third-party dependencies, you'll need to - * either use Webpack or the Angular CLI's `bundleDependencies` feature - * in order to adequately package them for use on the server without a - * node_modules directory. - * - * However, due to the nature of the CLI's `bundleDependencies`, importing - * Angular in this file will create a different instance of Angular than - * the version in the compiled application code. This leads to unavoidable - * conflicts. Therefore, please do not explicitly import from @angular or - * @nguniversal in this file. You can export any needed resources - * from your application's main.server.ts file, as seen below with the - * import for `ngExpressEngine`. - */ - import 'zone.js/dist/zone-node'; +import { ngExpressEngine } from '@nguniversal/express-engine'; import * as express from 'express'; -import {join} from 'path'; +import { join } from 'path'; -// Express server -const app = express(); +import { AppServerModule } from './src/main.server'; +import { APP_BASE_HREF } from '@angular/common'; -const PORT = process.env.PORT || 4000; -const DIST_FOLDER = join(process.cwd(), 'dist/browser'); +// The Express app is exported so that it can be used by serverless Functions. +export function app() { + const server = express(); + const distFolder = join(process.cwd(), 'dist/test-app/browser'); -// * NOTE :: leave this as require() since this file is built Dynamically from webpack -const {AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap} = require('./dist/server/main'); + // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) + server.engine('html', ngExpressEngine({ + bootstrap: AppServerModule, + })); -// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) -app.engine('html', ngExpressEngine({ - bootstrap: AppServerModuleNgFactory, - providers: [ - provideModuleMap(LAZY_MODULE_MAP) - ] -})); + server.set('view engine', 'html'); + server.set('views', distFolder); -app.set('view engine', 'html'); -app.set('views', DIST_FOLDER); + // Example Express Rest API endpoints + // app.get('/api/**', (req, res) => { }); + // Serve static files from /browser + server.get('*.*', express.static(distFolder, { + maxAge: '1y' + })); -// Example Express Rest API endpoints -// app.get('/api/**', (req, res) => { }); -// Serve static files from /browser -app.get('*.*', express.static(DIST_FOLDER, { - maxAge: '1y' -})); + // All regular routes use the Universal engine + server.get('*', (req, res) => { + res.render('index', { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); + }); -// All regular routes use the Universal engine -app.get('*', (req, res) => { - res.render('index', { req }); -}); + return server; +} -// Start up the Node server -app.listen(PORT, () => { - console.log(`Node Express server listening on http://localhost:${PORT}`); -}); +function run() { + const port = process.env.PORT || 4000; + + // Start up the Node server + const server = app(); + server.listen(port, () => { + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +// Webpack will replace 'require' with '__webpack_require__' +// '__non_webpack_require__' is a proxy to Node 'require' +// The below code is to ensure that the server is run only when not requiring the bundle. +declare const __non_webpack_require__: NodeRequire; +const mainModule = __non_webpack_require__.main; +if (mainModule && mainModule.filename === __filename) { + run(); +} + +export * from './src/main.server'; diff --git a/angular/test/test-app/src/app/app.server.module.ts b/angular/test/test-app/src/app/app.server.module.ts index caa1d19d12..246ad360b8 100644 --- a/angular/test/test-app/src/app/app.server.module.ts +++ b/angular/test/test-app/src/app/app.server.module.ts @@ -1,17 +1,13 @@ import { NgModule } from '@angular/core'; import { ServerModule } from '@angular/platform-server'; - import { IonicServerModule } from '@ionic/angular-server'; - import { AppModule } from './app.module'; import { AppComponent } from './app.component'; -import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader'; @NgModule({ imports: [ AppModule, ServerModule, - ModuleMapLoaderModule, IonicServerModule ], bootstrap: [AppComponent], diff --git a/angular/test/test-app/src/main.server.ts b/angular/test/test-app/src/main.server.ts index 33ed185061..10150a7181 100644 --- a/angular/test/test-app/src/main.server.ts +++ b/angular/test/test-app/src/main.server.ts @@ -7,5 +7,4 @@ if (environment.production) { } export { AppServerModule } from './app/app.server.module'; -export { ngExpressEngine } from '@nguniversal/express-engine'; -export { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; +export { renderModule, renderModuleFactory } from '@angular/platform-server'; diff --git a/angular/test/test-app/src/main.ts b/angular/test/test-app/src/main.ts index 38667018b0..e6659e9a13 100644 --- a/angular/test/test-app/src/main.ts +++ b/angular/test/test-app/src/main.ts @@ -10,6 +10,6 @@ if (environment.production) { document.addEventListener('DOMContentLoaded', () => { platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch(err => console.error(err)); + .bootstrapModule(AppModule) + .catch(err => console.error(err)); }); diff --git a/angular/test/test-app/src/polyfills.ts b/angular/test/test-app/src/polyfills.ts index aa665d6b87..14769a12ba 100644 --- a/angular/test/test-app/src/polyfills.ts +++ b/angular/test/test-app/src/polyfills.ts @@ -43,7 +43,7 @@ * * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames * * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js * with the following flag, it will bypass `zone.js` patch for IE/Edge @@ -52,9 +52,12 @@ * */ +import './zone-flags.ts'; + /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ + import 'zone.js/dist/zone'; // Included with Angular CLI. diff --git a/angular/test/test-app/src/zone-flags.ts b/angular/test/test-app/src/zone-flags.ts new file mode 100644 index 0000000000..e999ae9d11 --- /dev/null +++ b/angular/test/test-app/src/zone-flags.ts @@ -0,0 +1,5 @@ +/** + * Prevents Angular change detection from + * running with certain Web Component callbacks + */ +(window as any).__Zone_disable_customElements = true; diff --git a/angular/test/test-app/tsconfig.app.json b/angular/test/test-app/tsconfig.app.json index 8172e7a933..f74770a586 100644 --- a/angular/test/test-app/tsconfig.app.json +++ b/angular/test/test-app/tsconfig.app.json @@ -3,6 +3,10 @@ "compilerOptions": { "outDir": "./out-tsc/app" }, - "include": ["src/**/*.ts"], - "exclude": ["src/test.ts", "src/**/*.spec.ts"] + "files": [ + "src/main.ts", + "src/polyfills.ts", + "src/zone-flags.ts" + ], + "include": ["src/**/*.d.ts"] } diff --git a/angular/test/test-app/tsconfig.server.json b/angular/test/test-app/tsconfig.server.json index f868a9dad0..61aa6e8836 100644 --- a/angular/test/test-app/tsconfig.server.json +++ b/angular/test/test-app/tsconfig.server.json @@ -1,8 +1,16 @@ { "extends": "./tsconfig.app.json", "compilerOptions": { - "outDir": "../out-tsc/app-server" + "outDir": "./out-tsc/app-server", + "module": "commonjs", + "types": [ + "node" + ] }, + "files": [ + "src/main.server.ts", + "server.ts" + ], "angularCompilerOptions": { "entryModule": "./src/app/app.server.module#AppServerModule" } diff --git a/angular/test/test-app/webpack.server.config.js b/angular/test/test-app/webpack.server.config.js deleted file mode 100644 index dd80363015..0000000000 --- a/angular/test/test-app/webpack.server.config.js +++ /dev/null @@ -1,53 +0,0 @@ -// Work around for https://github.com/angular/angular-cli/issues/7200 - -const path = require('path'); -const webpack = require('webpack'); - -module.exports = { - mode: 'none', - entry: { - // This is our Express server for Dynamic universal - server: './server.ts' - }, - externals: { - './dist/server/main': 'require("./server/main")' - }, - target: 'node', - resolve: { - mainFields: ['module', 'main'], - extensions: ['.ts', '.js'] - }, - optimization: { - minimize: false - }, - output: { - // Puts the output at the root of the dist folder - path: path.join(__dirname, 'dist'), - filename: '[name].js' - }, - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { - // Mark files inside `@angular/core` as using SystemJS style dynamic imports. - // Removing this will cause deprecation warnings to appear. - test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/, - parser: { system: true }, - }, - ] - }, - plugins: [ - new webpack.ContextReplacementPlugin( - // fixes WARNING Critical dependency: the request of a dependency is an expression - /(.+)?angular(\\|\/)core(.+)?/, - path.join(__dirname, 'src'), // location of your src - {} // a map of your routes - ), - new webpack.ContextReplacementPlugin( - // fixes WARNING Critical dependency: the request of a dependency is an expression - /(.+)?express(\\|\/)(.+)?/, - path.join(__dirname, 'src'), - {} - ) - ] -}; diff --git a/angular/tsconfig.json b/angular/tsconfig.json index 60b910529d..9e6ab06cf5 100644 --- a/angular/tsconfig.json +++ b/angular/tsconfig.json @@ -1,11 +1,13 @@ { "angularCompilerOptions": { "annotateForClosureCompiler": true, - "strictMetadataEmit" : true, + "strictMetadataEmit": true, "flatModuleOutFile": "core.js", "flatModuleId": "@ionic/angular", "skipTemplateCodegen": true, - "fullTemplateTypeCheck": false + "fullTemplateTypeCheck": false, + "enableResourceInlining": true, + "enableIvy": false }, "compilerOptions": { "alwaysStrict": true, @@ -32,12 +34,8 @@ "target": "es2015", "baseUrl": ".", "paths": { - "@ionic/core/hydrate": [ - "../core/hydrate" - ], - "@ionic/core": [ - "../core" - ] + "@ionic/core/hydrate": ["../core/hydrate"], + "@ionic/core": ["../core"] } }, "exclude": ["node_modules", "src/schematics"], diff --git a/core/package.json b/core/package.json index d54733cd78..96199bfde1 100644 --- a/core/package.json +++ b/core/package.json @@ -34,7 +34,7 @@ "tslib": "^1.10.0" }, "devDependencies": { - "@stencil/core": "1.7.5", + "@stencil/core": "1.8.2-3", "@stencil/sass": "1.0.1", "@types/jest": "24.0.21", "@types/node": "12.12.3", diff --git a/docs/core.d.ts b/docs/core.d.ts new file mode 100644 index 0000000000..4f5068cc8f --- /dev/null +++ b/docs/core.d.ts @@ -0,0 +1,109 @@ + +/** + * This is an autogenerated file created by the Stencil compiler. + * DO NOT MODIFY IT MANUALLY + */ +export interface JsonDocs { + components: JsonDocsComponent[]; + timestamp: string; + compiler: { + name: string; + version: string; + typescriptVersion: string; + }; +} +export interface JsonDocsComponent { + dirPath?: string; + fileName?: string; + filePath?: string; + readmePath?: string; + usagesDir?: string; + encapsulation: 'shadow' | 'scoped' | 'none'; + tag: string; + readme: string; + docs: string; + docsTags: JsonDocsTag[]; + usage: JsonDocsUsage; + props: JsonDocsProp[]; + methods: JsonDocsMethod[]; + events: JsonDocsEvent[]; + styles: JsonDocsStyle[]; + slots: JsonDocsSlot[]; + dependents: string[]; + dependencies: string[]; + dependencyGraph: JsonDocsDependencyGraph; + deprecation?: string; +} +export interface JsonDocsDependencyGraph { + [tagName: string]: string[]; +} +export interface JsonDocsTag { + name: string; + text?: string; +} +export interface JsonDocsValue { + value?: string; + type: string; +} +export interface JsonDocsUsage { + [key: string]: string; +} +export interface JsonDocsProp { + name: string; + type: string; + mutable: boolean; + attr?: string; + reflectToAttr: boolean; + docs: string; + docsTags: JsonDocsTag[]; + default: string; + deprecation?: string; + values: JsonDocsValue[]; + optional: boolean; + required: boolean; +} +export interface JsonDocsMethod { + name: string; + docs: string; + docsTags: JsonDocsTag[]; + deprecation?: string; + signature: string; + returns: JsonDocsMethodReturn; + parameters: JsonDocMethodParameter[]; +} +export interface JsonDocsMethodReturn { + type: string; + docs: string; +} +export interface JsonDocMethodParameter { + name: string; + type: string; + docs: string; +} +export interface JsonDocsEvent { + event: string; + bubbles: boolean; + cancelable: boolean; + composed: boolean; + docs: string; + docsTags: JsonDocsTag[]; + deprecation?: string; + detail: string; +} +export interface JsonDocsStyle { + name: string; + docs: string; + annotation: string; +} +export interface JsonDocsSlot { + name: string; + docs: string; +} +export interface StyleDoc { + name: string; + docs: string; + annotation: 'prop'; +} + +declare const _default: JsonDocs; +export default _default; diff --git a/packages/angular-server/package.json b/packages/angular-server/package.json index dcc93ecd0e..4c9e734b7d 100644 --- a/packages/angular-server/package.json +++ b/packages/angular-server/package.json @@ -20,38 +20,40 @@ "url": "https://github.com/ionic-team/ionic/issues" }, "homepage": "https://ionicframework.com/", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], "scripts": { - "build": "ngc -p ./tsconfig.json", + "test": "echo 'angular no tests yet'", + "build": "ng-packagr -p package.json", "build.prod": "npm run clean && npm run build", - "clean": "rm -rf ./dist" + "clean": "rm -rf ./dist", + "lint": "npm run lint.ts", + "lint.ts": "tslint --project .", + "lint.fix": "tslint --project . --fix" + }, + "ngPackage": { + "lib": { + "entryFile": "src/public_api.ts" + } }, "peerDependencies": { - "@angular-devkit/core": "^8.0.0", - "@angular/common": "^8.0.0", - "@angular/core": "^8.0.0", - "@angular/platform-server": "^8.0.0", - "@ionic/core": "*", + "@angular/core": ">=8.2.7", + "@angular/platform-server": ">=8.2.7", + "@ionic/angular": "*", "rxjs": ">=6.2.0", "zone.js": ">=0.8.26" }, "devDependencies": { - "@angular-devkit/core": "^8.0.0", - "@angular/animations": "^8.0.0", - "@angular/common": "^8.0.0", - "@angular/compiler": "^8.0.0", - "@angular/compiler-cli": "^8.0.0", - "@angular/core": "^8.0.0", - "@angular/platform-browser": "^8.0.0", - "@angular/platform-server": "^8.0.0", - "@angular/router": "^8.0.0", - "rxjs": "^6.4.0", - "tsickle": "^0.34.0", - "typescript": "~3.4.3", - "zone.js": "~0.9.1" + "@angular/animations": "8.2.13", + "@angular/common": "8.2.13", + "@angular/compiler": "8.2.13", + "@angular/compiler-cli": "8.2.13", + "@angular/core": "8.2.13", + "@angular/platform-browser": "8.2.13", + "@angular/platform-server": "8.2.13", + "@ionic/core": "*", + "ng-packagr": "5.7.1", + "tslint": "^5.12.1", + "tslint-ionic-rules": "0.0.21", + "typescript": "3.4.5", + "typescript-tslint-plugin": "0.5.4" } } diff --git a/packages/angular-server/src/ionic-server-module.ts b/packages/angular-server/src/ionic-server-module.ts index d24a6cfccd..f334a57606 100644 --- a/packages/angular-server/src/ionic-server-module.ts +++ b/packages/angular-server/src/ionic-server-module.ts @@ -17,6 +17,7 @@ import { hydrateDocument } from '@ionic/core/hydrate'; export class IonicServerModule {} // @dynamic +// tslint:disable-next-line: only-arrow-functions export function hydrateIonicComponents(doc: any, appId: any) { return () => { return hydrateDocument(doc, { diff --git a/packages/angular-server/src/public_api.ts b/packages/angular-server/src/public_api.ts new file mode 100644 index 0000000000..f09f4e50d6 --- /dev/null +++ b/packages/angular-server/src/public_api.ts @@ -0,0 +1 @@ +export { IonicServerModule } from './ionic-server-module'; diff --git a/packages/angular-server/tsconfig.json b/packages/angular-server/tsconfig.json index ebab8e3196..f2e72c6652 100644 --- a/packages/angular-server/tsconfig.json +++ b/packages/angular-server/tsconfig.json @@ -1,9 +1,12 @@ { "extends": "../../tsconfig", "compilerOptions": { - "module": "CommonJS", + "module": "commonjs", "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "plugins": [ + { "name": "typescript-tslint-plugin" } + ] }, "files": [ "src/ionic-server-module.ts" @@ -16,4 +19,4 @@ "skipTemplateCodegen": true, "fullTemplateTypeCheck": false } -} \ No newline at end of file +} diff --git a/packages/angular-server/tslint.json b/packages/angular-server/tslint.json new file mode 100644 index 0000000000..909ec200f5 --- /dev/null +++ b/packages/angular-server/tslint.json @@ -0,0 +1,24 @@ +{ + "extends": ["tslint-ionic-rules/strict"], + "linterOptions": { + "exclude": [ + "**/*.spec.ts", + "**/*.spec.tsx" + ] + }, + "rules": { + "no-conditional-assignment": false, + "no-non-null-assertion": false, + "no-unnecessary-type-assertion": false, + "no-import-side-effect": false, + "trailing-comma": false, + "no-null-keyword": false, + "no-console": false, + "no-unbound-method": true, + "no-floating-promises": false, + "no-invalid-template-strings": true, + "ban-export-const-enum": true, + "only-arrow-functions": true, + "prefer-for-of": false + } +}