+ ```
+* **scss:** remove `scss` files from `dist/`, use CSS variables to theme instead. ([#19292](https://github.com/ionic-team/ionic/issues/19292)) ([6450aff](https://github.com/ionic-team/ionic/commit/6450aff080c561c60c140000b89ff340edeeaeca))
+* **skeleton-text:** remove `width` property. Use CSS instead. ([#18936](https://github.com/ionic-team/ionic/issues/18936)) ([7c3db79](https://github.com/ionic-team/ionic/commit/7c3db79c23dac599aa8131753b33b1ed3487d776))
+* **split-pane:** remove `main` attribute. Use `contentId` instead. ([#19511](https://github.com/ionic-team/ionic/issues/19511)) ([02d7841](https://github.com/ionic-team/ionic/commit/02d784140ce0fc75718781454e8dd8a2f621ee0d))
+
+ BEFORE:
+
+ ```html
+
+ ...
+ ...
+
+ ```
+
+ AFTER:
+
+ ```html
+
+ ...
+ ...
+
+ ```
+* **theming:** ionic default colors have been updated. ([#19279](https://github.com/ionic-team/ionic/issues/19279)) ([7f4cf08](https://github.com/ionic-team/ionic/commit/7f4cf08d996f90ae90064a351f8e373ce7a16799))
+* **toast:** remove `showCloseButton` and `closeButtonText`, add a button using the `buttons` property with `role: 'cancel'` instead. ([#18957](https://github.com/ionic-team/ionic/issues/18957)) ([ad7f112](https://github.com/ionic-team/ionic/commit/ad7f112e1eb04e41e697936454e63977d1bde34b))
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 5cdfe9ed037..04a99c8cba7 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,11 +1,129 @@
-# Contributor Code of Conduct
-As contributors and maintainers of the Ionic project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
+# Contributor Covenant Code of Conduct
-Communication through any of Ionic's channels (GitHub, Slack, Forum, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
+## Our Pledge
-We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Ionic project to do the same.
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
-If any member of the community violates this code of conduct, the maintainers of the Ionic project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
-If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at [hi@ionicframework.com](mailto:hi@ionicframework.com).
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include the ability to:
+
+* Demonstrate empathy and kindness towards people
+* Be respectful of differing opinions, viewpoints, and experiences
+* Give and gracefully accept constructive feedback
+* Accept responsibility and apologize to those affected by our mistakes,
+ and learn from the experience
+* Focus on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+[contact@ionic.io](mailto:contact@ionic.io).
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/LICENSE b/LICENSE
index 623c70a833c..92621d0bb42 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,23 +1,21 @@
-Copyright 2015-present Drifty Co.
-http://drifty.com/
-
MIT License
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
+Copyright (c) 2015-present Drifty Co.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
index f4ff97da7a0..23fcb151f97 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,98 @@
-# Ionic
-
-[Ionic](https://ionicframework.com/) is the open-source mobile app development framework that makes it easy to
-build top quality native and progressive web apps with web technologies.
-
-Ionic is based on [Web Components](https://www.webcomponents.org/introduction) and comes with many significant performance, usability, and feature improvements over the past versions.
-
+
+
+
+
+
+
+
+ Ionic
+
+
+
+ Ionic is an open source app development toolkit for building modern, fast, top-quality cross-platform native and Progressive Web Apps from a single codebase with JavaScript and the Web.
+
+
+ Ionic is based on Web Components , which enables significant performance, usability, and feature improvements alongside support for popular web frameworks like Angular , React , and Vue .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
### Packages
-| Project | Package | Version | Links |
-| ------- | ------- | ------- |:-----:|
-| **Core** | [`@ionic/core`](https://www.npmjs.com/package/@ionic/core) | [](https://www.npmjs.com/package/@ionic/core) | [`README.md`](core/README.md)
-| **Angular** | [`@ionic/angular`](https://www.npmjs.com/package/@ionic/angular) | [](https://www.npmjs.com/package/@ionic/angular) | [`README.md`](angular/README.md)
-| **Vue** | [`@ionic/vue`](https://www.npmjs.com/package/@ionic/vue) | [](https://www.npmjs.com/package/@ionic/vue) | [`README.md`](vue/README.md)
-| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [](https://www.npmjs.com/package/@ionic/react) | [`README.md`](packages/react/README.md)
+| Project | Package | Version | Downloads| Links |
+| ------- | ------- | ------- | -------- |:-----:|
+| **Core** | [`@ionic/core`](https://www.npmjs.com/package/@ionic/core) | [](https://www.npmjs.com/package/@ionic/core) | | [`README.md`](core/README.md)
+| **Angular** | [`@ionic/angular`](https://www.npmjs.com/package/@ionic/angular) | [](https://www.npmjs.com/package/@ionic/angular) | | [`README.md`](packages/angular/README.md)
+| **Vue** | [`@ionic/vue`](https://www.npmjs.com/package/@ionic/vue) | [](https://www.npmjs.com/package/@ionic/vue) | | [`README.md`](packages/vue/README.md)
+| **React** | [`@ionic/react`](https://www.npmjs.com/package/@ionic/react) | [](https://www.npmjs.com/package/@ionic/react) | |[`README.md`](packages/react/README.md)
Looking for the `ionic-angular` package? Ionic 3 has been moved to the [`ionic-v3`](https://github.com/ionic-team/ionic-v3) repo. See [Earlier Versions](#earlier-versions).
### Getting Started
-Start a new project by following our quick [Getting Started guide](https://ionicframework.com/getting-started/).
+Start a new project by following our [documentation](https://ionicframework.com/docs/).
We would love to hear from you! If you have any feedback or run into issues using our framework, please file
-an [issue](https://github.com/ionic-team/ionic/issues/new) on this repository.
+an [issue](https://github.com/ionic-team/ionic-framework/issues/new) on this repository.
+### Migration Guides
-### Contributing
-
-Thanks for your interest in contributing! Read up on our guidelines for
-[contributing](https://github.com/ionic-team/ionic/blob/master/.github/CONTRIBUTING.md)
-and then look through our issues with a [help wanted](https://github.com/ionic-team/ionic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
-label.
+Already have an Ionic app? These guides will help you migrate to the latest versions.
+* [Migrate from v7 to v8](https://ionicframework.com/docs/updating/8-0)
+* [Migrate from v6 to v7](https://ionicframework.com/docs/updating/7-0)
+* [Migrate from v5 to v6](https://ionicframework.com/docs/updating/6-0)
+* [Migrate from v4 to v5](https://ionicframework.com/docs/updating/5-0)
+* [Migrate from v3 to v4](https://ionicframework.com/docs/updating/4-0)
### Examples
-The [Ionic Conference App](https://github.com/ionic-team/ionic-conference-app) is a full featured Ionic app.
-It is the perfect starting point for learning and building your own app.
+The Ionic Conference App is a full featured Ionic app. It is the perfect starting point for learning and building your own app.
+
+- [Angular Ionic Conference App](https://github.com/ionic-team/ionic-conference-app)
+- [React Ionic Conference App](https://github.com/ionic-team/ionic-react-conference-app)
+- [Vue Ionic Conference App](https://github.com/ionic-team/ionic-vue-conference-app)
+### Contributing
-### Future Goals
+Thanks for your interest in contributing! Read up on our guidelines for
+[contributing](https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md)
+and then look through our issues with a [help wanted](https://github.com/ionic-team/ionic-framework/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
+label.
-As Ionic components migrate to the web component standard, a goal of ours is to have Ionic components easily work within all of the popular frameworks.
+Please note that this project is released with a [Contributor Code of Conduct](https://github.com/ionic-team/ionic-framework/blob/main/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
### Earlier Versions
diff --git a/angular/.npmrc b/angular/.npmrc
deleted file mode 100644
index 43c97e719a5..00000000000
--- a/angular/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-package-lock=false
diff --git a/angular/BREAKING.md b/angular/BREAKING.md
deleted file mode 100644
index b231ec21601..00000000000
--- a/angular/BREAKING.md
+++ /dev/null
@@ -1,1962 +0,0 @@
-
-# Breaking Changes
-
-## Migrating
-
-### Migration Guide
-
-If you aren't sure where to start in upgrading to v4, we recommend reading through our [migration guide](https://ionicframework.com/docs/building/migration) first.
-
-### Migration Linter
-
-Looking for a tool that automatically warns (and sometimes fixes) the breaking changes listed? Check out our [migration linter](https://github.com/ionic-team/v4-migration-tslint)!
-
-
-## Components
-
-A list of the breaking changes introduced to each component in Ionic Angular v4.
-
-- [Action Sheet](#action-sheet)
-- [Alert](#alert)
-- [Back Button](#back-button)
-- [Button](#button)
-- [Colors](#colors)
-- [Component Imports](#component-imports)
-- [Content](#content)
-- [Datetime](#datetime)
-- [Dynamic Mode](#dynamic-mode)
-- [FAB](#fab)
-- [Fixed Content](#fixed-content)
-- [Grid](#grid)
-- [Icon](#icon)
-- [Infinite Scroll](#infinite-scroll)
-- [Item](#item)
-- [Item Divider](#item-divider)
-- [Item Options](#item-options)
-- [Item Sliding](#item-sliding)
-- [Label](#label)
-- [List Header](#list-header)
-- [Loading](#loading)
-- [Menu](#menu)
-- [Menu Toggle](#menu-toggle)
-- [Modal](#modal)
-- [Nav](#nav)
-- [Navbar](#navbar)
-- [Option](#option)
-- [Overlays](#overlays)
-- [Popover](#popover)
-- [Radio](#radio)
-- [Range](#range)
-- [Refresher](#refresher)
-- [Scroll](#scroll)
-- [Segment Button](#segment-button)
-- [Select](#select)
-- [Show When / Hide When](#show-when--hide-when)
-- [Spinner](#spinner)
-- [Tabs](#tabs)
-- [Text / Typography](#text--typography)
-- [Theming](#theming)
-- [Toast](#toast)
-- [Toolbar](#toolbar)
-
-
-## Action Sheet
-
-The `title`, `subTitle` and `enableBackdropDismiss` properties have been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
-
-**Old Usage Example:**
-
-```js
-const actionSheet = await actionSheetCtrl.create({
- title: 'This is the title',
- subTitle: 'this is the sub title',
- enableBackdropDismiss: false
-});
-await actionSheet.present();
-```
-
-**New Usage Example:**
-
-```js
-const actionSheet = await actionSheetCtrl.create({
- header: 'This is the title',
- subHeader: 'this is the sub title',
- backdropDismiss: false
-});
-await actionSheet.present();
-```
-
-
-## Alert
-
-The `title`, `subTitle` and `enableBackdropDismiss` properties have been renamed to `header`, `subHeader` and `backdropDismiss` respectively.
-
-**Old Usage Example:**
-
-```js
-const alert = await alertCtrl.create({
- title: 'This is the title',
- subTitle: 'this is the sub title',
- enableBackdropDismiss: false
-});
-await alert.present();
-```
-
-**New Usage Example:**
-
-```js
-const alert = await alertCtrl.create({
- header: 'This is the title',
- subHeader: 'this is the sub title',
- backdropDismiss: false
-});
-await alert.present();
-```
-
-
-## Back Button
-
-The back button is no longer added by default to a navigation bar. It should be explicitly written in a toolbar:
-
-**Old Usage Example:**
-
-```html
-
- Back Button Example
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
- Back Button Example
-
-```
-
-See the [back button documentation](https://github.com/ionic-team/ionic/blob/master/core/src/components/back-button) for more usage examples.
-
-## Button
-
-### Markup Changed
-
-Button should now be written as an `` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute.
-
-**Old Usage Example:**
-
-```html
-
- Default Button
-
-
-
- Default Anchor
-
-```
-
-**New Usage Example:**
-
-```html
-
- Default Button
-
-
-
- Default Anchor
-
-```
-
-### Attributes Renamed
-
-Previously to style icons inside of a button the following attributes were used: `icon-left`, `icon-right`, (and with the added support of RTL) `icon-start`, `icon-end`.
-
-These have been renamed to the following, and moved from the button element to the icon itself:
-
-| Old Property | New Property | Property Behavior |
-|---------------------------|----------------|-----------------------------------------------------------------------|
-| `icon-left`, `icon-start` | `slot="start"` | Positions to the left of the button in LTR, and to the right in RTL. |
-| `icon-right`, `icon-end` | `slot="end"` | Positions to the right of the button in LTR, and to the left in RTL. |
-
-In addition, several sets of mutually exclusive boolean attributes have been combined into a single string attribute.
-
-The `small` and `large` attributes are now combined under the `size` attribute. The `clear`, `outline`, and `solid` attributes have been combined under `fill`. The `full` and `block` attributes have been combined under `expand`. And, lastly, the `round` attribute is now used under `shape`.
-
-| Old Property | New Property | Property Behavior |
-| --------------------------- | ------------ | --------------------------- |
-| `small`, `large` | `size` | Sets the button size. |
-| `clear`, `outline`, `solid` | `fill` | Sets the button fill style. |
-| `full`, `block` Β Β Β Β Β Β | `expand` | Sets the button width. |
-| `round` Β Β Β Β Β Β | `shape` | Sets the button shape. |
-
-
-**Old Usage Example:**
-
-```html
-
-
- Icon Left
-
-
-
-
- Icon Left on LTR, Right on RTL
-
-
-
- Icon Right
-
-
-
-
- Icon Right on LTR, Left on RTL
-
-
-
-
- Large Button
-
-
-
- Outline Button
-
-
-
- Full-width Button
-
-
-
- Round Button
-
-```
-
-**New Usage Example:**
-
-```html
-
-
- Icon Left on LTR, Right on RTL
-
-
-
- Icon Right on LTR, Left on RTL
-
-
-
-
- Large Button
-
-
-
- Outline Button
-
-
-
- Full-width Button
-
-
-
- Round Button
-
-```
-
-
-## Colors
-
-The default Ionic theme colors have changed. Previously we had:
-
-```
-primary: #327eff
-secondary: #32db64
-danger: #f53d3d
-light: #f4f4f4
-dark: #222
-```
-
-Some of their values have changed, and we now include more colors by default:
-
-```
-primary: #3880ff
-secondary: #0cd1e8
-tertiary: #7044ff
-success: #10dc60
-warning: #ffce00
-danger: #f04141
-light: #f4f5f8
-medium: #989aa2
-dark: #222428
-```
-
-The `secondary` color saw the largest change. If you were previously using our `secondary` color we recommend switching to `success` instead.
-
-
-## Component Imports
-
-For consistency with other frameworks and the rest of APIs and tooling, the exported
-Ionic components are now prefixed with `Ion`:
-
-```diff
-- import { Input, List, Slides } from 'ionic-angular';
-+ import { IonInput, IonList, IonSlides } from '@ionic/angular';
-```
-
-
-## Content
-
-Content is now a drop-in replacement for `ion-scroll`. This makes `ion-content` much more flexible. It can be used anywhere, even nested.
-
-### Method Removed
-
-The `resize` method has been removed from Content. In Ionic 4, the `ion-content` is based on a flex layout. This means the content size will automatically adjust without requiring a call to `resize()`.
-
-
-### Attributes Renamed
-
-
-| Old Property | New Property | Property Behavior |
-|--------------|-----------------------|-------------------------------------------------------------------------|
-| no-bounce | forceOverflow="false" | If true and the content does not cause an overflow scroll, the scroll interaction will cause a bounce. |
-
-
-## Datetime
-
-The Datetime classes and interfaces have changed capitalization from `DateTime` to `Datetime`. This is more consistent with other components and their tags.
-
-**Old Usage Example:**
-
-```javascript
-import { DateTime } from 'ionic-angular';
-```
-
-**New Usage Example:**
-
-```javascript
-import { Datetime } from '@ionic/angular';
-```
-
-
-## Dynamic Mode
-
-Components are no longer able to have their mode changed dynamically. You can change the mode before the first render, but after that it will not style properly because only the initial mode's styles are included.
-
-
-## Events
-
-Events now emit as a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) interface that extends the [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) interface. This interface includes a `detail` property that holds any data passed when the event is triggered.
-
-This allows you to still get the details of the event. For example, to get the target where the event was dispatched, such as a button that was clicked, you can read in the value of `event.target`.
-
-**Old Usage Example:**
-
-```html
-
-```
-
-```typescript
-onSelectChange(event) {
- const value = event.value;
- console.log('Select value is', value);
-}
-```
-
-**New Usage Example:**
-
-```typescript
-onSelectChange(event: CustomEvent) {
- const value = event.detail.value;
- console.log('Select value is', value);
-}
-```
-
-
-## FAB
-
-### Markup Changed
-
-Buttons inside of an `` container should now be written as an `` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute.
-
-**Old Usage Example:**
-
-```html
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-### Attributes Renamed
-
-The mutually exclusive boolean attributes to position the fab have been combined into two single string attributes.
-
-The attributes to align the fab horizontally are now combined under the `horizontal` attribute and the attributes to align the fab vertically are now combined under the `vertical` attribute:
-
-| Old Property | New Property | Property Behavior |
-|--------------|----------------------|-------------------------------------------------------------------------|
-| left | Removed, see `start` | |
-| right | Removed, see `end` | |
-| center | `horizontal="center"`| Positions to the center of the viewport. |
-| start | `horizontal="start"` | Positions to the left of the viewport in LTR, and to the right in RTL. |
-| end | `horizontal="end"` | Positions to the right of the viewport in LTR, and to the left in RTL. |
-| top | `vertical="top"` | Positions at the top of the viewport. |
-| bottom | `vertical="bottom"` | Positions at the bottom of the viewport. |
-| middle | `vertical="center"` | Positions at the center of the viewport. |
-
-_Note that `middle` has been changed to `center` for the vertical positioning._
-
-**Old Usage Example:**
-
-```html
-
-
-
-
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
-
-
-
-```
-
-## Fixed Content
-
-The `` container was previously placed inside of the fixed content by default. Now, any fixed content should use the `fixed` slot.
-
-**Old Usage Example:**
-
-```html
-
-
-
-
- Scrollable Content
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
- Scrollable Content
-
-```
-
-## Grid
-
-### Markup Changed
-
-The Grid has been refactored in order to support CSS variables and a dynamic number of columns. The following column attributes have been changed.
-
-_In the following examples, `{breakpoint}` refers to the optional screen breakpoint (xs, sm, md, lg, xl) and `{value}` refers to the number of columns (`auto` or a number between `1` and `12`)._
-
-- `col-{breakpoint}-{value}` attributes have been renamed to `size-{breakpoint}=β{value}β`
-- `offset-{breakpoint}-{value}` attributes have been renamed to `offset-{breakpoint}=β{value}β`
-- `push-{breakpoint}-{value}` attributes have been renamed to `push-{breakpoint}=β{value}β`
-- `pull-{breakpoint}-{value}` attributes have been renamed to `pull-{breakpoint}=β{value}β`
-
-Customizing the padding and width of a grid should now be done with CSS variables. For more information, see [Grid Layout](https://github.com/ionic-team/ionic-docs/blob/master/src/pages/layout/grid.md).
-
-## Icon
-
-### Fonts Removed
-
-Icons have been refactored to use SVGs instead of fonts. Ionic will only fetch the SVG for the icon when it is needed, instead of having a large font file that is always loaded in.
-
-If any `CSS` is being overridden for an icon it will need to change to override the SVG itself. Below is a usage example of the differences in changing the icon color.
-
-**Old Usage Example:**
-
-```css
-.icon {
- color: #000;
-}
-```
-
-**New Usage Example:**
-
-```css
-ion-icon {
- fill: #000;
-}
-```
-
-_Note: we are no longer adding the `icon` class to an `ion-icon`, so the element should be targeted instead._
-
-
-### Property Removed
-
-The `isActive` property has been removed. It only worked for `ios` icons previously. If you would like to switch between an outline and solid icon you should set it in the `name`, or `ios`/`md` attribute and then change it when needed.
-
-## Infinite Scroll
-
-### Method Removed
-
-The `enable()` method has been removed in favor of using the `disabled` property on the `ion-infinite-scroll` element.
-
-**Old Usage Example:**
-
-```html
-
-
-
-```
-
-```javascript
-doInfinite(infiniteScroll) {
- console.log('Begin async operation');
-
- setTimeout(() => {
- console.log('Async operation has ended');
- infiniteScroll.complete();
-
- // To disable the infinite scroll
- infiniteScroll.enable(false);
- }, 500);
-}
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-```
-
-```javascript
-doInfinite(event) {
- console.log('Begin async operation');
-
- setTimeout(() => {
- console.log('Async operation has ended');
- event.target.complete();
-
- // To disable the infinite scroll
- event.target.disabled = true;
- }, 500);
-}
-```
-
-
-## Item
-
-### Markup Changed
-
-Item should now be written as an `` element. Ionic will determine when to render an anchor tag based on the presence of an `href` attribute, and a button tag based on the presence of an `onclick` or `button` attribute. Otherwise, it will render a div.
-
-**Old Usage Example:**
-
-```html
-
- Default Item
-
-
-
- Button Item
-
-
-
- Anchor Item
-
-```
-
-**New Usage Example:**
-
-```html
-
-
- Default Item
-
-
-
-
-
- Button Item
-
-
-
-
-
- Anchor Item
-
-
-```
-
-### Label Required
-
-Previously an `ion-label` would automatically get added to an `ion-item` if one wasn't provided. Now an `ion-label` should always be added in the item component.
-
-```html
-
-
- Item Label
-
-
-```
-
-### Attributes Renamed
-
-Previously to position elements inside of an `ion-item` the following attributes were used: `item-left`, `item-right`, (and with the added support of RTL) `item-start`, `item-end`.
-
-These have been renamed to the following:
-
-| Old Property | New Property | Property Behavior |
-|---------------------------|----------------|---------------------------------------------------------------------|
-| `item-left`, `item-start` | `slot="start"` | Positions to the left of the item in LTR, and to the right in RTL. |
-| `item-right`, `item-end` | `slot="end"` | Positions to the right of the item in LTR, and to the left in RTL. |
-
-
-**Old Usage Example:**
-
-```html
-
- Left
- Item Label
- Right
-
-
-
- Left on LTR, Right on RTL
- Item Label
- Right on LTR, Left on RTL
-
-```
-
-**New Usage Example:**
-
-```html
-
- Left on LTR, Right on RTL
- Item Label
- Right on LTR, Left on RTL
-
-```
-
-### Detail Push
-
-The attributes to show/hide the detail arrows on items have been converted to a single property and value. Instead of writing `detail-push` or `detail-none` to show/hide the arrow, it should be written `detail`/`detail="true"` or `detail="false"`.
-
-**Old Usage Example:**
-
-```html
-
- Item Label
-
-
-
- Item Label
-
-```
-
-**New Usage Example:**
-
-```html
-
- Item Label
-
-
-
- Item Label
-
-```
-
-By default, items that render buttons or anchor tags will show the arrow in `ios` mode.
-
-## Item Divider
-
-### Label Required
-
-Previously an `ion-label` would automatically get added to an `ion-item-divider` if one wasn't provided. Now an `ion-label` should always be added around the text.
-
-```html
-
- Item Divider Label
-
-```
-
-
-## Item Options
-
-### Attributes Renamed
-
-Previously to position the item options inside of an `ion-item-sliding` the `side` attribute would be used with one of the following values: `"left"`, `"right"`.
-
-These values have been renamed to `"start"` and `"end"` to better align with our support for RTL.
-
-
-| Old Value | New Value |
-|-----------------|-----------------|
-| `side="left"` | `side="start"` |
-| `side="right"` | `side="end"` |
-
-
-## Item Sliding
-
-### Markup Changed
-
-The option component should now be written as an `ion-item-option`. Previously it was written as a `button` with an `ion-button` directive. The `ion-item-option` element will render a native button element inside of it.
-
-**Old Usage Example:**
-
-```html
-
-
- Item 1
-
-
-
-
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
- Item 1
-
-
-
-
-
-
-
-```
-
-### Method Renamed
-
-The `getSlidingPercent` method has been renamed to `getSlidingRatio` since the function is returning a ratio of the open amount of the item compared to the width of the options.
-
-### Arguments Changed
-
-The `ionDrag` event no longer gets the sliding item as an argument. It now takes an event with a property `details` which contains two properties `amount` and `ratio` reflecting the absolute and ratio values of the sliding action respectively.
-
-**Old Usage Example:**
-
-```typescript
-dragged(item: ItemSliding) {
- console.log(item.getSlidingPercent());
- console.log(item.getOpenAmount());
-}
-```
-
-**New Usage Example:**
-```typescript
-dragged(ev: { details: { amount: number, ratio: number } }) {
- console.log(ev.details.ratio);
- console.log(ev.details.amount);
-}
-```
-
-## Label
-
-### Attributes Renamed
-
-The attributes to set label position in an item are now combined under the `position` attribute:
-
-| Old Property | New Property | Property Behavior |
-|--------------|----------------------|------------------------------------------------------------------------------|
-| fixed | `position="fixed"` | A persistent label that sits next the input. |
-| floating | `position="floating"`| A label that will float above the input if the input is empty or loses focus.|
-| stacked | `position="stacked"` | A stacked label will always appear on top of the input. |
-
-**Old Usage Example:**
-
-```html
-
- Floating Label
-
-
-
-
- Fixed Label
-
-
-```
-
-**New Usage Example:**
-
-```html
-
- Floating Label
-
-
-
-
- Fixed Label
-
-
-```
-
-
-## List Header
-
-### Label Required
-
-Previously an `ion-label` would automatically get added to an `ion-list-header` if one wasn't provided. Now an `ion-label` should always be added around the text.
-
-```html
-
- List Header Label
-
-```
-
-## Loading
-
-See [Overlays](#overlays).
-
-
-## Menu
-
-### Properties Renamed
-
-- The `swipeEnabled` property has been renamed to `swipeGesture`.
-- The `content` prop has been renamed to `contentId` and it points to the DOM id of the content.
-
-**Old Usage Example:**
-
-```html
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-```
-
-
-### Events Renamed
-
-- `ionClose` was renamed to `ionDidClose`
-- `ionOpen` was renamed to `ionDidOpen`
-
-
-## Menu Toggle
-
-### Markup Changed
-
-The `menuToggle` attribute should not be added to an element anymore. Elements that should toggle a menu should be wrapped in an `ion-menu-toggle` element.
-
-**Old Usage Example:**
-
-```html
-
- Toggle Menu
-
-```
-
-**New Usage Example:**
-
-```html
-
-
- Toggle Menu
-
-
-```
-
-## Modal
-
-### Arguments Changed
-
-The component is no longer the first argument in the `create` method. Instead, a single argument of type `ModalOptions` is passed in with a `component` property and the value is the component as part of the passed object.
-
-**Old Usage Example:**
-
-```javascript
-import { Component } from '@angular/core';
-import { ModalController } from 'ionic-angular';
-
-import { ModalPage } from './modal-page';
-
-@Component({
- ...
-})
-export class MyPage {
-
- constructor(public modalCtrl: ModalController) { }
-
- presentModal() {
- const modal = this.modalCtrl.create(ModalPage);
- modal.present();
- }
-}
-```
-
-**New Usage Example:**
-
-```javascript
-import { Component } from '@angular/core';
-import { ModalController } from '@ionic/angular';
-
-import { ModalPage } from './modal-page';
-
-@Component({
- ...
-})
-export class MyPage {
-
- constructor(public modalCtrl: ModalController) { }
-
- async presentModal() {
- const modal = await this.modalCtrl.create({
- component: ModalPage
- });
- return await modal.present();
- }
-}
-```
-
-## Nav
-
-### Method Renamed
-
-- The `remove` method has been renamed to `removeIndex` to avoid conflicts with HTML and be more descriptive as to what it does.
-- The `getActiveChildNavs` method has been renamed to `getChildNavs`.
-
-### Prop Renamed
-
-- The `swipeBackEnabled` prop has been renamed to `swipeGesture`.
-
-
-## Navbar
-
-The `` component has been removed in favor of always using an `` with an explicit back button:
-
-**Old Usage Example:**
-
-```html
-
- My Navigation Bar
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
- My Navigation Bar
-
-```
-
-See the [back button](#back-button) changes for more information.
-
-
-## Option
-
-### Markup Changed
-
-Select's option element should now be written as ``. This makes it more obvious that the element should only be used with a Select.
-
-**Old Usage Example:**
-
-```html
-
- Option 1
- Option 2
- Option 3
-
-```
-
-**New Usage Example:**
-
-```html
-
- Option 1
- Option 2
- Option 3
-
-```
-
-### Class Renamed
-
-The class has been renamed from `Option` to `SelectOption` to keep it consistent with the element tag name.
-
-
-## Overlays
-
-### Markup Changed
-
-All overlays should now use `async`/`await`. This includes Action Sheet, Alert, Loading, Modal, Popover, and Toast. In addition, the `enableBackdropDismiss` property has been renamed to `backdropDismiss`.
-
-**Old Usage Example:**
-
-```javascript
-presentPopover(ev: any) {
- const popover = this.popoverController.create({
- component: PopoverComponent,
- event: event,
- translucent: true,
- enableBackdropDismiss: false
- });
- popover.present();
-}
-```
-
-**New Usage Example:**
-
-```javascript
-async presentPopover(ev: any) {
- const popover = await this.popoverController.create({
- component: PopoverComponent,
- event: event,
- translucent: true,
- backdropDismiss: false
- });
- return await popover.present();
-}
-```
-
-
-### Property Removed
-
-The `dismissOnPageChange` property of the create was removed from Loading & Toast. All of the navigation API is promise based and there are global events (`ionNavWillChange`, `ionNavDidChange`) that you can listen to in order to detect when navigation occurs.
-
-**Old Usage Example:**
-
-```javascript
-openLoading() {
- let loading = this.loadingCtrl.create({
- content: 'Loading...',
- dismissOnPageChange: true
- });
-}
-```
-
-**New Usage Example:**
-
-```javascript
-async openLoading() {
- let loading = this.loadingCtrl.create({
- message: 'Loading...'
- });
-
- await loading.present();
-
- const { role, data } = await loading.onDidDismiss();
-
- console.log('Loading dismissed!');
-}
-```
-
-
-## Popover
-
-See [Overlays](#overlays).
-
-
-## Radio
-
-### Slot Required
-
-Previously radio was positioned inside of an item automatically or by using `item-left`/`item-right`. It is now required to have a `slot` to be positioned properly in an item.
-
-**Old Usage Example:**
-
-```html
-
- Apple
-
-
-
-
- Grape, checked, disabled
-
-
-
-
- Cherry
-
-
-```
-
-**New Usage Example:**
-
-```html
-
- Apple
-
-
-
-
- Grape, checked, disabled
-
-
-
-
- Cherry
-
-
-```
-
-### Radio Group
-
-Radio group has been changed to an element. It should now be wrapped around any `` elements as ``.
-
-**Old Usage Example:**
-
-```html
-
-
- Apple
-
-
-
-
- Grape, checked, disabled
-
-
-
-
- Cherry
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
- Apple
-
-
-
-
- Grape, checked, disabled
-
-
-
-
- Cherry
-
-
-
-
-```
-
-
-## Range
-
-### Attributes Renamed
-
-Previously to place content inside of a range the following attributes were used: `range-left`, `range-right`, (and with the added support of RTL) `range-start`, `range-end`.
-
-These have been renamed to the following:
-
-| Old Property | New Property | Property Behavior |
-|-----------------------------|----------------|-----------------------------------------------------------------------|
-| `range-left`, `range-start` | `slot="start"` | Positions to the left of the range in LTR, and to the right in RTL. |
-| `range-right`, `range-end` | `slot="end"` | Positions to the right of the range in LTR, and to the left in RTL. |
-
-
-**Old Usage Example:**
-
-```html
-
-
-
-
-
-
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
-```
-
-
-## Refresher
-
-The `enabled` property (with a default value of `true`) has been renamed to `disabled` (with a default value of `false`).
-
-**Old Usage Example:**
-
-```html
-
- ...
-
-```
-
-**New Usage Example:**
-
-```html
-
- ...
-
-```
-
-## Scroll
-
-`ion-scroll` has been removed in favor of using `ion-content`:
-
-```diff
--
-+
-```
-
-Another very good option is to style a `div` to become scrollable using CSS:
-
-```css
-div.scrollable {
- overflow: scroll
-}
-```
-
-
-## Segment Button
-
-Segment Button text is now required to be wrapped in an `ion-label`.
-
-*Old usage:*
-
-```html
-
- Item One
-
-```
-
-*New usage:*
-
-```html
-
- Item One
-
-```
-
-
-## Select
-
-The `selectOptions` property was renamed to `interfaceOptions` since it directly correlates with the `interface` property.
-
-**Old Usage Example:**
-
-```html
-
- ...
-
-```
-
-```ts
-this.customOptions = {
- title: 'Pizza Toppings',
- subTitle: 'Select your toppings'
-};
-```
-
-**New Usage Example:**
-
-```html
-
- ...
-
-```
-
-```ts
-this.customOptions = {
- title: 'Pizza Toppings',
- subTitle: 'Select your toppings'
-};
-```
-
-## Show When / Hide When
-
-The `showWhen` and `hideWhen` directives (`ion-show-when` and `ion-hide-when` components) have been removed in v4 in favor of using CSS and [media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) to accomplish the desired look.
-
-### Media Query Examples
-
-Examples of media queries in CSS:
-
-```css
-/* targeting only portrait orientation */
-@media (orientation: portrait) {
- /* CSS to apply when orientation is portrait goes here */
-}
-
-/* targeting only landscape orientation */
-@media (orientation: landscape) {
- /* CSS to apply when orientation is landscape goes here */
-}
-
-/* targeting minimum width */
-@media (min-width: 300px) {
- /* CSS to apply when the minimum width is 300px goes here */
-}
-
-/* targeting both minimum width and maximum width */
-@media (min-width: 300px) and (max-width: 600px) {
- /* CSS to apply when the minimum width is 300px and maximum width is 600px goes here */
-}
-```
-
-### Showing and Hiding by Breakpoint
-
-The default breakpoints used by Ionic can be used internally if desired:
-
-| Breakpoint | Screen Width |
-| -----------| -------------|
-| `xs` | `0` |
-| `sm` | `576px` |
-| `md` | `768px` |
-| `lg` | `992px` |
-| `xl` | `1200px` |
-
-For example, to hide all `h3` elements when the minimum breakpoint is `sm`, the following CSS can be used:
-
-```css
-/* Hide all h3 elements when the minimum width is 576px (sm breakpoint) */
-@media (min-width: 576px) {
- h3 {
- display: none;
- }
-}
-```
-
-You can even create your own reusable classes for this, such as the following:
-
-```css
-/* Hide all elements with the .hide-xs-up class when the minimum width is 0px (xs breakpoint) */
-@media (min-width: 0px) {
- .hide-xs-up {
- display: none;
- }
-}
-
-/* Hide all elements with the .hide-sm-up class when the minimum width is 576px (sm breakpoint) */
-@media (min-width: 576px) {
- .hide-sm-up {
- display: none;
- }
-}
-
-/* Repeat above for the other breakpoints */
-```
-
-This can also be combined to only show specific elements when there is a min width:
-
-```css
-@media (min-width: 0px) {
- /* Hide all elements with the .hide-xs-up class when the minimum width is 0px (xs breakpoint) */
- .hide-xs-up {
- display: none;
- }
-
- /* Show all elements with the .show-xs-up class when the minimum width is 0px (xs breakpoint) */
- .show-xs-up {
- display: block;
- }
-}
-
-@media (min-width: 576px) {
- /* Hide all elements with the .hide-sm-up class when the minimum width is 576px (sm breakpoint) */
- .hide-sm-up {
- display: none;
- }
-
- /* Show all elements with the .show-sm-up class when the minimum width is 576px (sm breakpoint) */
- .show-sm-up {
- display: block;
- }
-}
-
-/* Repeat above for the other breakpoints */
-```
-
-If you'd only like to show the element when it is in that specific breakpoint, but don't want to add multiple classes to achieve it, you can combine `min-width` and `max-width` to target specific breakpoints:
-
-```css
-@media (min-width: 0px) and (max-width: 575px) {
- /* Hide all elements with the .hide-xs-only class when the minimum width is 0px (xs breakpoint) and the maximum width is 575px (right before sm breakpoint) */
- .show-xs-only {
- display: block;
- }
-}
-
-@media (min-width: 576px) and (max-width: 767px) {
- /* Hide all elements with the .hide-sm-only class when the minimum width is 576px (sm breakpoint) and the maximum width is 767px (right before md breakpoint) */
- .show-sm-only {
- display: block;
- }
-}
-
-@media (min-width: 768px) and (max-width: 991px) {
- /* Hide all elements with the .hide-md-only class when the minimum width is 768px (md breakpoint) and the maximum width is 991px (right before lg breakpoint) */
- .show-md-only {
- display: block;
- }
-}
-
-@media (min-width: 992px) and (max-width: 1199px) {
- /* Hide all elements with the .hide-lg-only class when the minimum width is 992px (lg breakpoint) and the maximum width is 1199px (right before xl breakpoint) */
- .show-lg-only {
- display: block;
- }
-}
-
-/* Not necessary for xl since there isn't a larger breakpoint, can use the show-xl-up */
-```
-
-### Showing and Hiding by Mode
-
-Styling based on the mode can be achieved by targeting an element with the mode class as the parent.
-
-For example, to hide all `h3` elements when the mode is `md`, the following CSS can be used:
-
-```css
-/* Hide all h3 elements when the mode is md */
-.md h3 {
- display: none;
-}
-```
-
-Similar to breakpoints, a class can be created to make this easier. For example, to hide all elements with the `.hide-ios` class in `ios` mode:
-
-```css
-/* Hide all elements when the mode is ios and they have the .hide-ios class */
-.ios .hide-ios {
- display: none;
-}
-```
-
-### Showing and Hiding by Platform
-
-Styling based on the platform is similar to styling by mode and can be achieved by targeting an element with the class `plt-{PLATFORM}` where {PLATFORM} is the name of the platform to be styled, from the following list:
-
-```
-ipad
-iphone
-ios
-android
-phablet
-tablet
-cordova
-capacitor
-electron
-pwa
-mobile
-desktop
-hybrid
-```
-
-For example, to hide all `h3` elements when the platform is `desktop`, the following CSS can be used:
-
-```css
-/* Hide all h3 elements when the platform is desktop */
-.plt-desktop h3 {
- display: none;
-}
-```
-
-
-## Spinner
-
-### Name Changed
-
-The `ios` and `ios-small` spinner's have been renamed to `lines` and `lines-small`, respectively. This also applies to any components that use spinner: `ion-loading`, `ion-infinite-scroll`, `ion-refresher`.
-
-**Old Usage Example:**
-
-```html
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-```
-
-
-## Tabs
-
-Tabs has been completely refactored for Ionic 4. In Ionic 3 there was a lot of magic going on behind the scenes to style and generate the tab bar and buttons. While this made it easy to get up and running using tabs in Ionic, it made it more difficult to customize the tabs.
-
-We decided to rethink the tabs implementation to make it more flexible and easier to theme for your application. In order to accomplish this, there had to be some changes to the markup.
-
-
-### `ion-tabs`
-
-The general usage of the `ion-tabs` element hasn't changed too drastically. Its purpose is still mostly the same - it wraps the entire layout.
-
-#### Properties Removed
-
-The attributes to position the tabs, change the tab layout, enable the tab highlight and hide the tabs have been removed. Instead customize this content in the [ion-tab-button](#ion-tab-button).
-
-**Old Usage Example:**
-
-```html
-
- ...
-
-```
-
-**New Usage Example:**
-
-```html
-
- ...
-
-```
-
-
-### `ion-tab`
-
-The `ion-tab` has been removed in the Angular version of Ionic 4. You should use the Angular router with an [ion-tab-button](#ion-tab-button) that has a `tab` property.
-
-```typescript
-import { RouterModule, Routes } from '@angular/router';
-
-import { TabsPage } from './tabs.page';
-
-const routes: Routes = [
- {
- path: 'tabs',
- component: TabsPage,
- children: [
- {
- path: 'tab1',
- children: [
- {
- path: '',
- loadChildren: '../tab1/tab1.module#Tab1PageModule'
- }
- ]
- },
- {
- path: 'tab2',
- children: [
- {
- path: '',
- loadChildren: '../tab2/tab2.module#Tab2PageModule'
- }
- ]
- },
- {
- path: 'tab3',
- children: [
- {
- path: '',
- loadChildren: '../tab3/tab3.module#Tab3PageModule'
- }
- ]
- },
- {
- path: '',
- redirectTo: '/tabs/tab1',
- pathMatch: 'full'
- }
- ]
- },
- {
- path: '',
- redirectTo: '/tabs/tab1',
- pathMatch: 'full'
- }
-];
-```
-
-```html
-
-
-
-
- Tab One
-
-
-
-
- Tab Two
-
-
-
-
- Tab Three
-
-
-
-```
-
-### `ion-tab-bar`
-
-A new element, `ion-tab-bar`, creates the tab bar that will contain the tab buttons and allow for full customization. It requires `slot` to be placed properly above or below the content.
-
-### `ion-tab-button`
-
-A new element, `ion-tab-button`, is used to create each button in the tab bar. These could be static links to different routes, buttons with click handlers on them, or link to whole tab views.
-
-You can add `` and `` inside of an ``. An `` should be wrapped by an ``.
-
-The tab attribute defines the route to be shown upon clicking on this tab.
-
-**Old Usage Example:**
-
-```html
-
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
-
- Map
- 2
-
-
-
-```
-
-See more usage examples in the [Tabs](https://github.com/ionic-team/ionic/blob/master/core/src/components/tabs) documentation.
-
-
-## Text / Typography
-
-### Markup Changed
-
-Typography should now be written as an `` element. Previously the `ion-text` attribute could be added to any HTML element to set its color. It should now be used as a wrapper around the HTML elements to style.
-
-**Old Usage Example:**
-
-```html
-H1: The quick brown fox jumps over the lazy dog
-
-H2: The quick brown fox jumps over the lazy dog
-
-H3: The quick brown fox jumps over the lazy dog
-
-
- I saw a werewolf with a Chinese menu in his hand.
- Walking through the streets of Soho in the rain.
- He was looking for a place called Lee Ho Fook's.
- Gonna get a big dish of beef chow mein.
-
-```
-
-**New Usage Example:**
-
-```html
-
- H1: The quick brown fox jumps over the lazy dog
-
-
-
- H2: The quick brown fox jumps over the lazy dog
-
-
-
- H3: The quick brown fox jumps over the lazy dog
-
-
-
- I saw a werewolf with a Chinese menu in his hand.
- Walking through the streets of Soho in the rain.
- He was looking for a place called Lee Ho Fook's.
- Gonna get a big dish of beef chow mein.
-
-```
-
-
-## Theming
-
-### Global CSS
-
-Many of the components in Ionic 4 have self-contained styles thanks to [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
-
-However, there are still global styles that need to be included in order for an Ionic app to look and behave properly. The global styles include normalizing elements, typography, colors, and more.
-
-#### Basic CSS Files
-
-The basic set of CSS files should be included to ensure the Ionic application behaves natively.
-
-- **core.css**
-Contains styles for the font, structure, and the `color` property for all Ionic components.
-
-- **normalize.css**
-Normalizes the CSS differences between browsers, it's based on https://necolas.github.io/normalize.css/
-
-- **structure.css**
-Applies styles to the `` element and defaults `box-sizing` to `border-box`. It's used to ensure scrolling behaves natively on mobile devices.
-
-- **typography.css**
-Changes the `font-family` of the whole page based on the mode selected (iOS or Material Design). It also applies global styles to native HTML elements.
-
-
-#### Additional CSS Files
-
-The following set of CSS files are optional and can safely be commented out if the application is not using any of the features.
-
-- **padding.css**
-Adds utility attributes that allow adding `padding` and `margin` attributes to any element. See [content space](https://ionicframework.com/docs/layout/css-utilities#content-space) for what this includes.
-
-- **float-elements.css**
-Adds utility attributes that allow adding `float` attributes to any element. See [element placement](https://ionicframework.com/docs/layout/css-utilities/#element-placement) for what this includes.
-
-- **text-alignment.css**
-Adds utility attributes that allow adding text alignment attributes to any element. See [text alignment](https://ionicframework.com/docs/layout/css-utilities/#text-alignment) for what this includes.
-
-- **text-transformation.css**
-Adds utility attributes that allow adding text transformation attributes to any element. See [text transformation](https://ionicframework.com/docs/layout/css-utilities/#text-transformation) for what this includes.
-
-- **flex-utils.css**
-Adds utility attributes that allow adding flex container and item attributes to any element. See [flex properties](https://ionicframework.com/docs/layout/css-utilities/#flex-properties) for what this includes.
-
-
-#### Including the CSS Files
-
-Official Ionic starters are already properly configured so the following steps are not needed.
-
-#### Testing
-
-To include the stylesheet for testing such as in a Plunker, Codepen, or anywhere else:
-
-```html
-
-```
-
-#### Production
-
-To use the CSS in production, we recommend importing it into a global file, such as `app/global.scss`:
-
-```css
-/** Basic CSS for Ionic Apps */
-@import "~@ionic/angular/css/core.css";
-@import "~@ionic/angular/css/normalize.css";
-@import "~@ionic/angular/css/structure.css";
-@import "~@ionic/angular/css/typography.css";
-
-/** Optional CSS utilities that can be commented out */
-@import "~@ionic/angular/css/padding.css";
-@import "~@ionic/angular/css/float-elements.css";
-@import "~@ionic/angular/css/text-alignment.css";
-@import "~@ionic/angular/css/text-transformation.css";
-@import "~@ionic/angular/css/flex-utils.css";
-```
-
-
-### CSS Utilities
-
-#### Padding
-
-Previously to add padding to the left and right side of elements, the `padding-left` and `padding-right` attributes, respectively, would be added to the element.
-
-These attributes have been renamed to `padding-start` and `padding-end` to better align with our support for RTL.
-
-#### Margin
-
-Previously to add margin to the left and right side of elements, the `margin-left` and `margin-right` attributes, respectively, would be added to the element.
-
-These attributes have been removed in favor of using the `margin-start` and `margin-end` attributes to better align with our support for RTL.
-
-
-### Including Sass
-
-Previously all `scss` files in the `src` directory were imported. Now each `scss` file should be included for the component via Angular's `styleUrls` metadata. View [Angular's Component Styles](https://angular.io/guide/component-styles) for more information.
-
-This means that any styles wrapped with a page should now be removed since they will automatically be scoped to the component.
-
-**Old Usage Example:**
-
-```scss
-page-schedule {
- p {
- color: red;
- }
-}
-```
-
-**New Usage Example:**
-
-```scss
-p {
- color: red;
-}
-```
-
-
-### Sass Variables
-
-Sass variables should no longer be used to change Ionic components. We have built Ionic to be customizable using CSS variables, instead.
-
-For more information on theming, check out the [theming documentation](https://ionicframework.com/docs/theming/basics).
-
-
-## Toast
-
-See [Overlays](#overlays).
-
-
-## Toolbar
-
-### Menu Toggle
-
-Previously if a `menuToggle` directive was added to an Ionic `button` in a toolbar, it would be positioned outside of the `ion-buttons` element. Since menu toggle is simply a wrapper to a button now, it should be placed inside of the `ion-buttons` element.
-
-**Old Usage Example:**
-
-```html
-
-
-
-
- Left side menu toggle
-
-```
-
-**New Usage Example:**
-
-```html
-
-
-
-
-
-
-
-
- Left side menu toggle
-
-```
-
-### Attributes Renamed
-
-Previously to positions buttons inside of a toolbar the following attributes were used: `start`, `left`, `right`, `end`.
-
-These have been renamed to the following:
-
-| Old Property | New Property | Property Behavior |
-|--------------|--------------------|----------------------------------------------------------------------------------------------------------|
-| `start` | `slot="secondary"` | Positions element to the `left` of the content in `ios` mode, and directly to the `right` in `md` mode. |
-| `end` | `slot="primary"` | Positions element to the `right` of the content in `ios` mode, and to the far `right` in `md` mode. |
-| `left` | `slot="start"` | Positions to the `left` of the content in LTR, and to the `right` in RTL. |
-| `right` | `slot="end"` | Positions to the `right` of the content in LTR, and to the `left` in RTL. |
-
-**Old Usage Example:**
-
-```html
-
-
- Left
-
-
- Secondary
-
-
-
- Title
-
-
-
- Primary
-
-
- Right
-
-
-```
-
-**New Usage Example:**
-
-```html
-
-
- Left
-
-
- Secondary
-
-
-
- Title
-
-
-
- Primary
-
-
- Right
-
-
-```
diff --git a/angular/README.md b/angular/README.md
deleted file mode 100644
index 6c185f8977f..00000000000
--- a/angular/README.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# @ionic/angular
-
-Ionic Angular specific building blocks on top of [@ionic/core](https://www.npmjs.com/package/@ionic/core) components.
-
-
-## Related
-
-* [Ionic Core Components](https://www.npmjs.com/package/@ionic/core)
-* [Ionic Documentation](https://ionicframework.com/docs/)
-* [Ionic Worldwide Slack](http://ionicworldwide.herokuapp.com/)
-* [Ionic Forum](https://forum.ionicframework.com/)
-* [Ionicons](http://ionicons.com/)
-* [Stencil](https://stenciljs.com/)
-* [Stencil Worldwide Slack](https://stencil-worldwide.herokuapp.com/)
-* [Capacitor](https://capacitor.ionicframework.com/)
-
-
-## License
-
-* [MIT](https://raw.githubusercontent.com/ionic-team/ionic/master/LICENSE)
-
-## Testing ng-add in ionic
-
-1. Pull the latest from master
-2. Build ionic/angular: `npm run build`
-3. Run `npm link` from `ionic/angular/dist` directory
-4. Create a blank angular project
-
-```
-ng new add-test
-// Say yes to including the router, we need it
-cd add-test
-```
-
-5. To run schematics locally, we need the schematics-cli (once published, this will not be needed)
-
-```
-npm install @angular-devkit/schematics-cli
-```
-
-6. Link `@ionic/angular`
-
-```
-npm link @ionic/angular
-```
-
-
-7. Run the local copy of the ng-add schematic
-
-```
-$ npx schematics @ionic/angular:ng-add
-```
-
-
-You'll now be able to add ionic components to a vanilla Angular app setup.
diff --git a/angular/package.json b/angular/package.json
deleted file mode 100644
index 8e846147e13..00000000000
--- a/angular/package.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "name": "@ionic/angular",
- "version": "5.0.7",
- "description": "Angular specific wrappers for @ionic/core",
- "keywords": [
- "ionic",
- "framework",
- "angular",
- "mobile",
- "app",
- "webapp",
- "capacitor",
- "cordova",
- "progressive web app",
- "pwa"
- ],
- "license": "MIT",
- "repository": {
- "type": "git",
- "url": "https://github.com/ionic-team/ionic.git"
- },
- "bugs": {
- "url": "https://github.com/ionic-team/ionic/issues"
- },
- "homepage": "https://ionicframework.com/",
- "scripts": {
- "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": "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",
- "clean-generated": "node ./scripts/clean-generated.js",
- "lint": "npm run lint.ts",
- "lint.ts": "tslint --project .",
- "lint.fix": "tslint --project . --fix",
- "prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
- "test": "echo 'angular no tests yet'",
- "tsc": "tsc -p .",
- "validate": "npm i && npm run lint && npm run test && npm run build"
- },
- "dependencies": {
- "@ionic/core": "5.0.7",
- "tslib": "^1.9.3"
- },
- "peerDependencies": {
- "@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": "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.4.5",
- "zone.js": "^0.8.28"
- },
- "schematics": "./schematics/collection.json",
- "ngPackage": {
- "lib": {
- "entryFile": "src/index.ts"
- },
- "whitelistedNonPeerDependencies": [
- "@ionic/core"
- ]
- }
-}
diff --git a/angular/scripts/README.md b/angular/scripts/README.md
deleted file mode 100644
index 95acfc6eb6e..00000000000
--- a/angular/scripts/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Local @ionic/angular test/testapp development
-
-1. `npm install` at the root of `angular`
-2. `npm run build.dev` to build local `@ionic/angular` and `@ionic/core`
-3. `cd test/testapp` to the test app
-4. `npm install` in the test app directory
-5. `npm run serve` copies packages and serve the app (see package.json for more options)
-6. [http://localhost:4200/](http://localhost:4200/)
-
-
-# npm link local development
-
-`npm link` doesn't work as expected due to the `devDependency` on `@angular/core`. This is the work around...
-
- npm run build.link ../ionic-conference-app
-
-When the command above is ran from the `angular` directory, it will build `@ionic/angular` and copy the `dist` directory to the correct location of another local project. In the example above, the end result is that it copies the `dist` directory to `../ionic-conference-app/node_modules/@ionic/angular/dist`. The path given should be relative to the root of this mono repo.
-
-## package.json note
-
-The `package.json` file in this directory references __Ionic 3__ and is in here to get GitHub to properly show the Used By counts on the repo. __Do not remove it!__
diff --git a/angular/scripts/link-copy.js b/angular/scripts/link-copy.js
deleted file mode 100644
index 5465e00a1af..00000000000
--- a/angular/scripts/link-copy.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const fs = require('fs-extra');
-const path = require('path');
-
-
-let prjDir = process.argv[2];
-if (!prjDir) {
- throw new Error('local path required as last argument to "npm run build.link" command');
-}
-prjDir = path.join(__dirname, '../../../', prjDir);
-
-copyPackage(prjDir, 'angular');
-copyPackage(prjDir, 'core');
-
-
-function copyPackage(prjDir, pkgName) {
- const prjDest = path.join(prjDir, 'node_modules', '@ionic', pkgName);
-
- const pkgSrcDir = path.join(__dirname, '..', '..', pkgName);
- const pkgSrcDist = path.join(pkgSrcDir, 'dist');
- const pkgJsonPath = path.join(pkgSrcDir, 'package.json');
- const pkgJson = require(pkgJsonPath);
-
- // make sure this local project exists
- fs.emptyDirSync(prjDest);
-
- pkgJson.files.push('package.json');
-
- pkgJson.files.forEach(f => {
- const src = path.join(pkgSrcDir, f);
- const dest = path.join(prjDest, f);
-
- console.log('copying:', src, 'to', dest);
- fs.copySync(src, dest);
- });
-
- const prjReadme = path.join(prjDest, 'README.md');
- console.log('readme:', prjReadme);
-
- fs.writeFileSync(prjReadme, '@ionic/' + pkgName + ' copied from ' + pkgSrcDir + ', ' + new Date());
-}
diff --git a/angular/scripts/package.json b/angular/scripts/package.json
deleted file mode 100644
index 67c7b04246d..00000000000
--- a/angular/scripts/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "ionic-angular",
- "version": "`gulp package` generates dist/package.json from this template using the root ./package.json",
- "description": "",
- "keywords": [],
- "repository": {
- "type": "git",
- "url": "https://github.com/ionic-team/ionic.git"
- },
- "license": "MIT",
- "main": "umd/index.js",
- "module": "index.js",
- "es2015": "es2015/index.js",
- "peerDependencies": {
- }
-}
diff --git a/angular/scripts/rollup.config.js b/angular/scripts/rollup.config.js
deleted file mode 100644
index 0a80b0c5300..00000000000
--- a/angular/scripts/rollup.config.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import resolve from 'rollup-plugin-node-resolve';
-
-export default {
- input: 'build/es2015/core.js',
- output: [
- {
- file: 'dist/fesm2015.js',
- format: 'es'
- }
- ],
- external: (id) => {
- // anything else is external
- // Windows: C:\xxxxxx\xxx
- const colonPosition = 1;
- return !(id.startsWith('.') || id.startsWith('/') || id.charAt(colonPosition) === ':');
- },
- plugins: [
- resolve({
- mainFields: ['module']
- })
- ]
-};
diff --git a/angular/src/app-initialize.ts b/angular/src/app-initialize.ts
deleted file mode 100644
index 362a9ab5cc2..00000000000
--- a/angular/src/app-initialize.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { NgZone } from '@angular/core';
-import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
-
-import { Config } from './providers/config';
-import { IonicWindow } from './types/interfaces';
-import { raf } from './util/util';
-
-let didInitialize = false;
-
-export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
- return (): any => {
- const win: IonicWindow | undefined = doc.defaultView as any;
- if (win && typeof (window as any) !== 'undefined') {
- if (didInitialize) {
- console.warn('Ionic Angular was already initialized. Make sure IonicModule.forRoot() is just called once.');
- }
- didInitialize = true;
- const Ionic = win.Ionic = win.Ionic || {};
-
- Ionic.config = {
- ...config,
- _zoneGate: (h: any) => zone.run(h)
- };
-
- const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
- ? '__zone_symbol__addEventListener'
- : 'addEventListener';
-
- return applyPolyfills().then(() => {
- return defineCustomElements(win, {
- exclude: ['ion-tabs', 'ion-tab'],
- syncQueue: true,
- raf,
- jmp: (h: any) => zone.runOutsideAngular(h),
- ael(elm, eventName, cb, opts) {
- (elm as any)[aelFn](eventName, cb, opts);
- },
- rel(elm, eventName, cb, opts) {
- elm.removeEventListener(eventName, cb, opts);
- }
- });
- });
- }
- };
-};
diff --git a/angular/src/directives/control-value-accessors/boolean-value-accessor.ts b/angular/src/directives/control-value-accessors/boolean-value-accessor.ts
deleted file mode 100644
index 74d1d5066ad..00000000000
--- a/angular/src/directives/control-value-accessors/boolean-value-accessor.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Directive, ElementRef, HostListener } from '@angular/core';
-import { NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { ValueAccessor, setIonicClasses } from './value-accessor';
-
-@Directive({
- /* tslint:disable-next-line:directive-selector */
- selector: 'ion-checkbox,ion-toggle',
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: BooleanValueAccessor,
- multi: true
- }
- ]
-})
-export class BooleanValueAccessor extends ValueAccessor {
-
- constructor(el: ElementRef) {
- super(el);
- }
-
- writeValue(value: any) {
- this.el.nativeElement.checked = this.lastValue = value == null ? false : value;
- setIonicClasses(this.el);
- }
-
- @HostListener('ionChange', ['$event.target'])
- _handleIonChange(el: any) {
- this.handleChangeEvent(el, el.checked);
- }
-}
diff --git a/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts b/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts
deleted file mode 100644
index 7f667eb73a0..00000000000
--- a/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Directive, ElementRef, HostListener } from '@angular/core';
-import { NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { ValueAccessor } from './value-accessor';
-
-@Directive({
- /* tslint:disable-next-line:directive-selector */
- selector: 'ion-input[type=number]',
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: NumericValueAccessor,
- multi: true
- }
- ]
-})
-export class NumericValueAccessor extends ValueAccessor {
-
- constructor(el: ElementRef) {
- super(el);
- }
-
- @HostListener('ionChange', ['$event.target'])
- _handleIonChange(el: any) {
- this.handleChangeEvent(el, el.value);
- }
-
- registerOnChange(fn: (_: number | null) => void) {
- super.registerOnChange(value => {
- fn(value === '' ? null : parseFloat(value));
- });
- }
-}
diff --git a/angular/src/directives/control-value-accessors/radio-value-accessor.ts b/angular/src/directives/control-value-accessors/radio-value-accessor.ts
deleted file mode 100644
index ae68034ba3f..00000000000
--- a/angular/src/directives/control-value-accessors/radio-value-accessor.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Directive, ElementRef, HostListener } from '@angular/core';
-import { NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { ValueAccessor } from './value-accessor';
-
-@Directive({
- /* tslint:disable-next-line:directive-selector */
- selector: 'ion-radio',
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: RadioValueAccessor,
- multi: true
- }
- ]
-})
-export class RadioValueAccessor extends ValueAccessor {
-
- constructor(el: ElementRef) {
- super(el);
- }
-
- @HostListener('ionSelect', ['$event.target'])
- _handleIonSelect(el: any) {
- this.handleChangeEvent(el, el.checked);
- }
-}
diff --git a/angular/src/directives/control-value-accessors/select-value-accessor.ts b/angular/src/directives/control-value-accessors/select-value-accessor.ts
deleted file mode 100644
index fddc1644858..00000000000
--- a/angular/src/directives/control-value-accessors/select-value-accessor.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Directive, ElementRef, HostListener } from '@angular/core';
-import { NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { ValueAccessor } from './value-accessor';
-
-@Directive({
- /* tslint:disable-next-line:directive-selector */
- selector: 'ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime',
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: SelectValueAccessor,
- multi: true
- }
- ]
-})
-export class SelectValueAccessor extends ValueAccessor {
-
- constructor(el: ElementRef) {
- super(el);
- }
-
- @HostListener('ionChange', ['$event.target'])
- _handleChangeEvent(el: any) {
- this.handleChangeEvent(el, el.value);
- }
-}
diff --git a/angular/src/directives/control-value-accessors/text-value-accessor.ts b/angular/src/directives/control-value-accessors/text-value-accessor.ts
deleted file mode 100644
index 7981a60510a..00000000000
--- a/angular/src/directives/control-value-accessors/text-value-accessor.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Directive, ElementRef, HostListener } from '@angular/core';
-import { NG_VALUE_ACCESSOR } from '@angular/forms';
-
-import { ValueAccessor } from './value-accessor';
-
-@Directive({
- /* tslint:disable-next-line:directive-selector */
- selector: 'ion-input:not([type=number]),ion-textarea,ion-searchbar',
- providers: [
- {
- provide: NG_VALUE_ACCESSOR,
- useExisting: TextValueAccessor,
- multi: true
- }
- ]
-})
-export class TextValueAccessor extends ValueAccessor {
-
- constructor(el: ElementRef) {
- super(el);
- }
-
- @HostListener('ionChange', ['$event.target'])
- _handleInputEvent(el: any) {
- this.handleChangeEvent(el, el.value);
- }
-}
diff --git a/angular/src/directives/control-value-accessors/value-accessor.ts b/angular/src/directives/control-value-accessors/value-accessor.ts
deleted file mode 100644
index ca159d301c9..00000000000
--- a/angular/src/directives/control-value-accessors/value-accessor.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { ElementRef, HostListener } from '@angular/core';
-import { ControlValueAccessor } from '@angular/forms';
-
-import { raf } from '../../util/util';
-
-export class ValueAccessor implements ControlValueAccessor {
-
- private onChange: (value: any) => void = () => {/**/};
- private onTouched: () => void = () => {/**/};
- protected lastValue: any;
-
- constructor(protected el: ElementRef) {}
-
- writeValue(value: any) {
- /**
- * TODO for Ionic 6:
- * Change `value == null ? '' : value;`
- * to `value`. This was a fix for IE9, but IE9
- * is no longer supported; however, this change
- * is potentially a breaking change
- */
- this.el.nativeElement.value = this.lastValue = value == null ? '' : value;
- setIonicClasses(this.el);
- }
-
- handleChangeEvent(el: HTMLElement, value: any) {
- if (el === this.el.nativeElement) {
- if (value !== this.lastValue) {
- this.lastValue = value;
- this.onChange(value);
- }
- setIonicClasses(this.el);
- }
- }
-
- @HostListener('ionBlur', ['$event.target'])
- _handleBlurEvent(el: any) {
- if (el === this.el.nativeElement) {
- this.onTouched();
- setIonicClasses(this.el);
- }
- }
-
- registerOnChange(fn: (value: any) => void) {
- this.onChange = fn;
- }
-
- registerOnTouched(fn: () => void) {
- this.onTouched = fn;
- }
-
- setDisabledState(isDisabled: boolean) {
- this.el.nativeElement.disabled = isDisabled;
- }
-}
-
-export const setIonicClasses = (element: ElementRef) => {
- raf(() => {
- const input = element.nativeElement as HTMLElement;
- const classes = getClasses(input);
- setClasses(input, classes);
-
- const item = input.closest('ion-item');
- if (item) {
- setClasses(item, classes);
- }
- });
-};
-
-const getClasses = (element: HTMLElement) => {
- const classList = element.classList;
- const classes = [];
- for (let i = 0; i < classList.length; i++) {
- const item = classList.item(i);
- if (item !== null && startsWith(item, 'ng-')) {
- classes.push(`ion-${item.substr(3)}`);
- }
- }
- return classes;
-};
-
-const setClasses = (element: HTMLElement, classes: string[]) => {
- const classList = element.classList;
- [
- 'ion-valid',
- 'ion-invalid',
- 'ion-touched',
- 'ion-untouched',
- 'ion-dirty',
- 'ion-pristine'
- ].forEach(c => classList.remove(c));
-
- classes.forEach(c => classList.add(c));
-};
-
-const startsWith = (input: string, search: string): boolean => {
- return input.substr(0, search.length) === search;
-};
diff --git a/angular/src/directives/navigation/ion-back-button.ts b/angular/src/directives/navigation/ion-back-button.ts
deleted file mode 100644
index d4ba31407cf..00000000000
--- a/angular/src/directives/navigation/ion-back-button.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Directive, HostListener, Optional } from '@angular/core';
-
-import { Config } from '../../providers/config';
-import { NavController } from '../../providers/nav-controller';
-
-import { IonRouterOutlet } from './ion-router-outlet';
-
-@Directive({
- selector: 'ion-back-button',
- inputs: ['defaultHref'],
-})
-export class IonBackButtonDelegate {
-
- defaultHref: string | undefined | null;
-
- constructor(
- @Optional() private routerOutlet: IonRouterOutlet,
- private navCtrl: NavController,
- private config: Config
- ) {}
-
- /**
- * @internal
- */
- @HostListener('click', ['$event'])
- onClick(ev: Event) {
- const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');
-
- if (this.routerOutlet && this.routerOutlet.canGoBack()) {
- this.routerOutlet.pop();
- ev.preventDefault();
- } else if (defaultHref != null) {
- this.navCtrl.navigateBack(defaultHref);
- ev.preventDefault();
- }
- }
-}
diff --git a/angular/src/directives/navigation/ion-router-outlet.ts b/angular/src/directives/navigation/ion-router-outlet.ts
deleted file mode 100644
index 24002ada53b..00000000000
--- a/angular/src/directives/navigation/ion-router-outlet.ts
+++ /dev/null
@@ -1,353 +0,0 @@
-import { Location } from '@angular/common';
-import { Attribute, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
-import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
-import { BehaviorSubject, Observable } from 'rxjs';
-import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
-
-import { AnimationBuilder } from '../../';
-import { Config } from '../../providers/config';
-import { NavController } from '../../providers/nav-controller';
-
-import { StackController } from './stack-controller';
-import { RouteView, getUrl } from './stack-utils';
-
-@Directive({
- selector: 'ion-router-outlet',
- exportAs: 'outlet',
- inputs: ['animated', 'animation', 'swipeGesture']
-})
-export class IonRouterOutlet implements OnDestroy, OnInit {
- nativeEl: HTMLIonRouterOutletElement;
-
- private activated: ComponentRef | null = null;
- private activatedView: RouteView | null = null;
-
- private _activatedRoute: ActivatedRoute | null = null;
- private _swipeGesture?: boolean;
- private name: string;
- private stackCtrl: StackController;
-
- // Maintain map of activated route proxies for each component instance
- private proxyMap = new WeakMap();
-
- // Keep the latest activated route in a subject for the proxy routes to switch map to
- private currentActivatedRoute$ = new BehaviorSubject<{ component: any; activatedRoute: ActivatedRoute } | null>(null);
-
- tabsPrefix: string | undefined;
-
- @Output() stackEvents = new EventEmitter();
- @Output('activate') activateEvents = new EventEmitter();
- @Output('deactivate') deactivateEvents = new EventEmitter();
-
- set animation(animation: AnimationBuilder) {
- this.nativeEl.animation = animation;
- }
-
- set animated(animated: boolean) {
- this.nativeEl.animated = animated;
- }
-
- set swipeGesture(swipe: boolean) {
- this._swipeGesture = swipe;
-
- this.nativeEl.swipeHandler = swipe ? {
- canStart: () => this.stackCtrl.canGoBack(1),
- onStart: () => this.stackCtrl.startBackTransition(),
- onEnd: shouldContinue => this.stackCtrl.endBackTransition(shouldContinue)
- } : undefined;
- }
-
- constructor(
- private parentContexts: ChildrenOutletContexts,
- private location: ViewContainerRef,
- private resolver: ComponentFactoryResolver,
- @Attribute('name') name: string,
- @Optional() @Attribute('tabs') tabs: string,
- private config: Config,
- private navCtrl: NavController,
- commonLocation: Location,
- elementRef: ElementRef,
- router: Router,
- zone: NgZone,
- activatedRoute: ActivatedRoute,
- @SkipSelf() @Optional() readonly parentOutlet?: IonRouterOutlet
- ) {
- this.nativeEl = elementRef.nativeElement;
- this.name = name || PRIMARY_OUTLET;
- this.tabsPrefix = tabs === 'true' ? getUrl(router, activatedRoute) : undefined;
- this.stackCtrl = new StackController(this.tabsPrefix, this.nativeEl, router, navCtrl, zone, commonLocation);
- parentContexts.onChildOutletCreated(this.name, this as any);
- }
-
- ngOnDestroy(): void {
- this.stackCtrl.destroy();
- }
-
- getContext(): OutletContext | null {
- return this.parentContexts.getContext(this.name);
- }
-
- ngOnInit(): void {
- if (!this.activated) {
- // If the outlet was not instantiated at the time the route got activated we need to populate
- // the outlet when it is initialized (ie inside a NgIf)
- const context = this.getContext();
- if (context && context.route) {
- this.activateWith(context.route, context.resolver || null);
- }
- }
- if ((this.nativeEl as any).componentOnReady) {
- this.nativeEl.componentOnReady().then(() => {
- if (this._swipeGesture === undefined) {
- this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
- }
- });
- }
- }
-
- get isActivated(): boolean {
- return !!this.activated;
- }
-
- get component(): object {
- if (!this.activated) {
- throw new Error('Outlet is not activated');
- }
- return this.activated.instance;
- }
-
- get activatedRoute(): ActivatedRoute {
- if (!this.activated) {
- throw new Error('Outlet is not activated');
- }
- return this._activatedRoute as ActivatedRoute;
- }
-
- get activatedRouteData(): any {
- if (this._activatedRoute) {
- return this._activatedRoute.snapshot.data;
- }
- return {};
- }
-
- /**
- * Called when the `RouteReuseStrategy` instructs to detach the subtree
- */
- detach(): ComponentRef {
- throw new Error('incompatible reuse strategy');
- }
-
- /**
- * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
- */
- attach(_ref: ComponentRef, _activatedRoute: ActivatedRoute) {
- throw new Error('incompatible reuse strategy');
- }
-
- deactivate(): void {
- if (this.activated) {
- if (this.activatedView) {
- this.activatedView.savedData = new Map(this.getContext()!.children['contexts']);
-
- /**
- * Ensure we are saving the NavigationExtras
- * data otherwise it will be lost
- */
- this.activatedView.savedExtras = {};
- const context = this.getContext()!;
-
- if (context.route) {
- const contextSnapshot = context.route.snapshot;
-
- this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams;
- this.activatedView.savedExtras.fragment = contextSnapshot.fragment;
- }
- }
- const c = this.component;
- this.activatedView = null;
- this.activated = null;
- this._activatedRoute = null;
- this.deactivateEvents.emit(c);
- }
- }
-
- activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null) {
- if (this.isActivated) {
- throw new Error('Cannot activate an already activated outlet');
- }
- this._activatedRoute = activatedRoute;
-
- let cmpRef: any;
- let enteringView = this.stackCtrl.getExistingView(activatedRoute);
- if (enteringView) {
- cmpRef = this.activated = enteringView.ref;
- const saved = enteringView.savedData;
- if (saved) {
- // self-restore
- const context = this.getContext()!;
- context.children['contexts'] = saved;
- }
- // Updated activated route proxy for this component
- this.updateActivatedRouteProxy(cmpRef.instance, activatedRoute);
- } else {
- const snapshot = (activatedRoute as any)._futureSnapshot;
- const component = snapshot.routeConfig!.component as any;
- resolver = resolver || this.resolver;
-
- const factory = resolver.resolveComponentFactory(component);
- const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
-
- // We create an activated route proxy object that will maintain future updates for this component
- // over its lifecycle in the stack.
- const component$ = new BehaviorSubject(null);
- const activatedRouteProxy = this.createActivatedRouteProxy(component$, activatedRoute);
-
- const injector = new OutletInjector(activatedRouteProxy, childContexts, this.location.injector);
- cmpRef = this.activated = this.location.createComponent(factory, this.location.length, injector);
-
- // Once the component is created we can push it to our local subject supplied to the proxy
- component$.next(cmpRef.instance);
-
- // Calling `markForCheck` to make sure we will run the change detection when the
- // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
- enteringView = this.stackCtrl.createView(this.activated, activatedRoute);
-
- // Store references to the proxy by component
- this.proxyMap.set(cmpRef.instance, activatedRouteProxy);
- this.currentActivatedRoute$.next({ component: cmpRef.instance, activatedRoute });
- }
-
- this.activatedView = enteringView;
- this.stackCtrl.setActive(enteringView).then(data => {
- this.navCtrl.setTopOutlet(this);
- this.activateEvents.emit(cmpRef.instance);
- this.stackEvents.emit(data);
- });
- }
-
- /**
- * Returns `true` if there are pages in the stack to go back.
- */
- canGoBack(deep = 1, stackId?: string): boolean {
- return this.stackCtrl.canGoBack(deep, stackId);
- }
-
- /**
- * Resolves to `true` if it the outlet was able to sucessfully pop the last N pages.
- */
- pop(deep = 1, stackId?: string): Promise {
- return this.stackCtrl.pop(deep, stackId);
- }
-
- /**
- * Returns the URL of the active page of each stack.
- */
- getLastUrl(stackId?: string): string | undefined {
- const active = this.stackCtrl.getLastUrl(stackId);
- return active ? active.url : undefined;
- }
-
- /**
- * Returns the RouteView of the active page of each stack.
- * @internal
- */
- getLastRouteView(stackId?: string): RouteView | undefined {
- return this.stackCtrl.getLastUrl(stackId);
- }
-
- /**
- * Returns the root view in the tab stack.
- * @internal
- */
- getRootView(stackId?: string): RouteView | undefined {
- return this.stackCtrl.getRootUrl(stackId);
- }
-
- /**
- * Returns the active stack ID. In the context of ion-tabs, it means the active tab.
- */
- getActiveStackId(): string | undefined {
- return this.stackCtrl.getActiveStackId();
- }
-
- /**
- * Since the activated route can change over the life time of a component in an ion router outlet, we create
- * a proxy so that we can update the values over time as a user navigates back to components already in the stack.
- */
- private createActivatedRouteProxy(component$: Observable, activatedRoute: ActivatedRoute): ActivatedRoute {
- const proxy: any = new ActivatedRoute();
-
- proxy._futureSnapshot = (activatedRoute as any)._futureSnapshot;
- proxy._routerState = (activatedRoute as any)._routerState;
- proxy.snapshot = activatedRoute.snapshot;
- proxy.outlet = activatedRoute.outlet;
- proxy.component = activatedRoute.component;
-
- // Setup wrappers for the observables so consumers don't have to worry about switching to new observables as the state updates
- (proxy as any)._paramMap = this.proxyObservable(component$, 'paramMap');
- (proxy as any)._queryParamMap = this.proxyObservable(component$, 'queryParamMap');
- proxy.url = this.proxyObservable(component$, 'url');
- proxy.params = this.proxyObservable(component$, 'params');
- proxy.queryParams = this.proxyObservable(component$, 'queryParams');
- proxy.fragment = this.proxyObservable(component$, 'fragment');
- proxy.data = this.proxyObservable(component$, 'data');
-
- return proxy as ActivatedRoute;
- }
-
- /**
- * Create a wrapped observable that will switch to the latest activated route matched by the given component
- */
- private proxyObservable(component$: Observable, path: string): Observable {
- return component$.pipe(
- // First wait until the component instance is pushed
- filter(component => !!component),
- switchMap(component =>
- this.currentActivatedRoute$.pipe(
- filter(current => current !== null && current.component === component),
- switchMap(current => current && (current.activatedRoute as any)[path]),
- distinctUntilChanged()
- )
- )
- );
- }
-
- /**
- * Updates the activated route proxy for the given component to the new incoming router state
- */
- private updateActivatedRouteProxy(component: any, activatedRoute: ActivatedRoute): void {
- const proxy = this.proxyMap.get(component);
- if (!proxy) {
- throw new Error(`Could not find activated route proxy for view`);
- }
-
- (proxy as any)._futureSnapshot = (activatedRoute as any)._futureSnapshot;
- (proxy as any)._routerState = (activatedRoute as any)._routerState;
- proxy.snapshot = activatedRoute.snapshot;
- proxy.outlet = activatedRoute.outlet;
- proxy.component = activatedRoute.component;
-
- this.currentActivatedRoute$.next({ component, activatedRoute });
- }
-}
-
-class OutletInjector implements Injector {
- constructor(
- private route: ActivatedRoute,
- private childContexts: ChildrenOutletContexts,
- private parent: Injector
- ) { }
-
- get(token: any, notFoundValue?: any): any {
- if (token === ActivatedRoute) {
- return this.route;
- }
-
- if (token === ChildrenOutletContexts) {
- return this.childContexts;
- }
-
- // tslint:disable-next-line
- return this.parent.get(token, notFoundValue);
- }
-}
diff --git a/angular/src/directives/navigation/ion-tabs.ts b/angular/src/directives/navigation/ion-tabs.ts
deleted file mode 100644
index 016901bea4f..00000000000
--- a/angular/src/directives/navigation/ion-tabs.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-import { Component, ContentChild, EventEmitter, HostListener, Output, ViewChild } from '@angular/core';
-
-import { NavController } from '../../providers/nav-controller';
-import { IonTabBar } from '../proxies';
-
-import { IonRouterOutlet } from './ion-router-outlet';
-import { StackEvent } from './stack-utils';
-
-@Component({
- selector: 'ion-tabs',
- template: `
-
-
-
-
- `,
- styles: [`
- :host {
- display: flex;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-
- flex-direction: column;
-
- width: 100%;
- height: 100%;
-
- contain: layout size style;
- z-index: $z-index-page-container;
- }
- .tabs-inner {
- position: relative;
-
- flex: 1;
-
- contain: layout size style;
- }`
- ]
-})
-export class IonTabs {
-
- @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 }>();
-
- constructor(
- private navCtrl: NavController,
- ) { }
-
- /**
- * @internal
- */
- onPageSelected(detail: StackEvent) {
- const stackId = detail.enteringView.stackId;
- if (detail.tabSwitch && stackId !== undefined) {
- if (this.tabBar) {
- this.tabBar.selectedTab = stackId;
- }
- this.ionTabsWillChange.emit({ tab: stackId });
- this.ionTabsDidChange.emit({ tab: stackId });
- }
- }
-
- /**
- * When a tab button is clicked, there are several scenarios:
- * 1. If the selected tab is currently active (the tab button has been clicked
- * again), then it should go to the root view for that tab.
- *
- * a. Get the saved root view from the router outlet. If the saved root view
- * matches the tabRootUrl, set the route view to this view including the
- * navigation extras.
- * b. If the saved root view from the router outlet does
- * not match, navigate to the tabRootUrl. No navigation extras are
- * included.
- *
- * 2. If the current tab tab is not currently selected, get the last route
- * view from the router outlet.
- *
- * a. If the last route view exists, navigate to that view including any
- * navigation extras
- * b. If the last route view doesn't exist, then navigate
- * to the default tabRootUrl
- */
- @HostListener('ionTabButtonClick', ['$event.detail.tab'])
- select(tab: string) {
- const alreadySelected = this.outlet.getActiveStackId() === tab;
- const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
- if (alreadySelected) {
- const activeStackId = this.outlet.getActiveStackId();
- const activeView = this.outlet.getLastRouteView(activeStackId);
-
- // If on root tab, do not navigate to root tab again
- if (activeView.url === tabRootUrl) { return; }
-
- const rootView = this.outlet.getRootView(tab);
- const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
- return this.navCtrl.navigateRoot(tabRootUrl, {
- ...(navigationExtras),
- animated: true,
- animationDirection: 'back',
- });
- } else {
- const lastRoute = this.outlet.getLastRouteView(tab);
- /**
- * If there is a lastRoute, goto that, otherwise goto the fallback url of the
- * selected tab
- */
- const url = lastRoute && lastRoute.url || tabRootUrl;
- const navigationExtras = lastRoute && lastRoute.savedExtras;
-
- return this.navCtrl.navigateRoot(url, {
- ...(navigationExtras),
- animated: true,
- animationDirection: 'back',
- });
- }
- }
-
- getSelected(): string | undefined {
- return this.outlet.getActiveStackId();
- }
-}
diff --git a/angular/src/directives/navigation/nav-delegate.ts b/angular/src/directives/navigation/nav-delegate.ts
deleted file mode 100644
index e12964f10d4..00000000000
--- a/angular/src/directives/navigation/nav-delegate.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-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'
-})
-export class NavDelegate {
- protected el: HTMLElement;
- constructor(
- ref: ElementRef,
- resolver: ComponentFactoryResolver,
- injector: Injector,
- 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/navigation/router-link-delegate.ts b/angular/src/directives/navigation/router-link-delegate.ts
deleted file mode 100644
index b3c73c7bb79..00000000000
--- a/angular/src/directives/navigation/router-link-delegate.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { LocationStrategy } from '@angular/common';
-import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
-import { Router, RouterLink } from '@angular/router';
-import { RouterDirection } from '@ionic/core';
-import { Subscription } from 'rxjs';
-
-import { NavController } from '../../providers/nav-controller';
-
-@Directive({
- selector: '[routerLink]',
- inputs: ['routerDirection']
-})
-export class RouterLinkDelegate {
-
- private subscription?: Subscription;
-
- routerDirection: RouterDirection = 'forward';
-
- constructor(
- private locationStrategy: LocationStrategy,
- private navCtrl: NavController,
- private elementRef: ElementRef,
- private router: Router,
- @Optional() private routerLink?: RouterLink,
- ) { }
-
- ngOnInit() {
- this.updateTargetUrlAndHref();
- }
-
- ngOnChanges(): any {
- this.updateTargetUrlAndHref();
- }
-
- ngOnDestroy(): any {
- if (this.subscription) {
- this.subscription.unsubscribe();
- }
- }
-
- private updateTargetUrlAndHref() {
- if (this.routerLink) {
- const href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.routerLink.urlTree));
- this.elementRef.nativeElement.href = href;
- }
- }
-
- /**
- * @internal
- */
- @HostListener('click', ['$event'])
- onClick(ev: UIEvent) {
- this.navCtrl.setDirection(this.routerDirection);
- ev.preventDefault();
- }
-}
diff --git a/angular/src/directives/navigation/stack-controller.ts b/angular/src/directives/navigation/stack-controller.ts
deleted file mode 100644
index 3465bbe371b..00000000000
--- a/angular/src/directives/navigation/stack-controller.ts
+++ /dev/null
@@ -1,307 +0,0 @@
-import { Location } from '@angular/common';
-import { ComponentRef, NgZone } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterDirection } from '@ionic/core';
-
-import { bindLifecycleEvents } from '../../providers/angular-delegate';
-import { NavController } from '../../providers/nav-controller';
-
-import { RouteView, StackEvent, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
-
-export class StackController {
-
- private views: RouteView[] = [];
- private runningTask?: Promise;
- private skipTransition = false;
- private tabsPrefix: string[] | undefined;
- private activeView: RouteView | undefined;
- private nextId = 0;
-
- constructor(
- tabsPrefix: string | undefined,
- private containerEl: HTMLIonRouterOutletElement,
- private router: Router,
- private navCtrl: NavController,
- private zone: NgZone,
- private location: Location
- ) {
- this.tabsPrefix = tabsPrefix !== undefined ? toSegments(tabsPrefix) : undefined;
- }
-
- createView(ref: ComponentRef, activatedRoute: ActivatedRoute): RouteView {
- const url = getUrl(this.router, activatedRoute);
- const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
- const unlistenEvents = bindLifecycleEvents(this.zone, ref.instance, element);
- return {
- id: this.nextId++,
- stackId: computeStackId(this.tabsPrefix, url),
- unlistenEvents,
- element,
- ref,
- url,
- };
- }
-
- getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
- const activatedUrlKey = getUrl(this.router, activatedRoute);
- const view = this.views.find(vw => vw.url === activatedUrlKey);
- if (view) {
- view.ref.changeDetectorRef.reattach();
- }
- return view;
- }
-
- setActive(enteringView: RouteView): Promise {
- let { direction, animation } = this.navCtrl.consumeTransition();
- const leavingView = this.activeView;
- const tabSwitch = isTabSwitch(enteringView, leavingView);
- if (tabSwitch) {
- direction = 'back';
- animation = undefined;
- }
-
- const viewsSnapshot = this.views.slice();
-
- let currentNavigation;
-
- const router = (this.router as any);
-
- // Angular >= 7.2.0
- if (router.getCurrentNavigation) {
- currentNavigation = router.getCurrentNavigation();
-
- // Angular < 7.2.0
- } else if (
- router.navigations &&
- router.navigations.value
- ) {
- currentNavigation = router.navigations.value;
- }
-
- /**
- * If the navigation action
- * sets `replaceUrl: true`
- * then we need to make sure
- * we remove the last item
- * from our views stack
- */
- if (
- currentNavigation &&
- currentNavigation.extras &&
- currentNavigation.extras.replaceUrl
- ) {
- if (this.views.length > 0) {
- this.views.splice(-1, 1);
- }
- }
-
- const reused = this.views.includes(enteringView);
- const views = this.insertView(enteringView, direction);
-
- // Trigger change detection before transition starts
- // This will call ngOnInit() the first time too, just after the view
- // was attached to the dom, but BEFORE the transition starts
- if (!reused) {
- enteringView.ref.changeDetectorRef.detectChanges();
- }
-
- // Wait until previous transitions finish
- return this.zone.runOutsideAngular(() => {
- return this.wait(() => {
- // disconnect leaving page from change detection to
- // reduce jank during the page transition
- if (leavingView) {
- leavingView.ref.changeDetectorRef.detach();
- }
- // In case the enteringView is the same as the leavingPage we need to reattach()
- enteringView.ref.changeDetectorRef.reattach();
-
- return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
- .then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
- .then(() => ({
- enteringView,
- direction,
- animation,
- tabSwitch
- }));
- });
- });
- }
-
- canGoBack(deep: number, stackId = this.getActiveStackId()): boolean {
- return this.getStack(stackId).length > deep;
- }
-
- pop(deep: number, stackId = this.getActiveStackId()) {
- return this.zone.run(() => {
- const views = this.getStack(stackId);
- if (views.length <= deep) {
- return Promise.resolve(false);
- }
- const view = views[views.length - deep - 1];
- let url = view.url;
-
- const viewSavedData = view.savedData;
- if (viewSavedData) {
- const primaryOutlet = viewSavedData.get('primary');
- if (
- primaryOutlet &&
- primaryOutlet.route &&
- primaryOutlet.route._routerState &&
- primaryOutlet.route._routerState.snapshot &&
- primaryOutlet.route._routerState.snapshot.url
- ) {
- url = primaryOutlet.route._routerState.snapshot.url;
- }
- }
-
- return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true);
- });
- }
-
- startBackTransition() {
- const leavingView = this.activeView;
- if (leavingView) {
- const views = this.getStack(leavingView.stackId);
- const enteringView = views[views.length - 2];
- return this.wait(() => {
- return this.transition(
- enteringView, // entering view
- leavingView, // leaving view
- 'back',
- this.canGoBack(2),
- true
- );
- });
- }
- return Promise.resolve();
- }
-
- endBackTransition(shouldComplete: boolean) {
- if (shouldComplete) {
- this.skipTransition = true;
- this.pop(1);
- } else if (this.activeView) {
- cleanup(this.activeView, this.views, this.views, this.location);
- }
- }
-
- getLastUrl(stackId?: string) {
- const views = this.getStack(stackId);
- return views.length > 0 ? views[views.length - 1] : undefined;
- }
-
- /**
- * @internal
- */
- getRootUrl(stackId?: string) {
- const views = this.getStack(stackId);
- return views.length > 0 ? views[0] : undefined;
- }
-
- getActiveStackId(): string | undefined {
- return this.activeView ? this.activeView.stackId : undefined;
- }
-
- destroy() {
- this.containerEl = undefined!;
- this.views.forEach(destroyView);
- this.activeView = undefined;
- this.views = [];
- }
-
- private getStack(stackId: string | undefined) {
- return this.views.filter(v => v.stackId === stackId);
- }
-
- private insertView(enteringView: RouteView, direction: RouterDirection) {
- this.activeView = enteringView;
- this.views = insertView(this.views, enteringView, direction);
- return this.views.slice();
- }
-
- private transition(
- enteringView: RouteView | undefined,
- leavingView: RouteView | undefined,
- direction: 'forward' | 'back' | undefined,
- showGoBack: boolean,
- progressAnimation: boolean
- ) {
- if (this.skipTransition) {
- this.skipTransition = false;
- return Promise.resolve(false);
- }
- if (leavingView === enteringView) {
- return Promise.resolve(false);
- }
- const enteringEl = enteringView ? enteringView.element : undefined;
- const leavingEl = leavingView ? leavingView.element : undefined;
- const containerEl = this.containerEl;
- if (enteringEl && enteringEl !== leavingEl) {
- enteringEl.classList.add('ion-page');
- enteringEl.classList.add('ion-page-invisible');
- if (enteringEl.parentElement !== containerEl) {
- containerEl.appendChild(enteringEl);
- }
-
- if ((containerEl as any).commit) {
- return containerEl.commit(enteringEl, leavingEl, {
- deepWait: true,
- duration: direction === undefined ? 0 : undefined,
- direction,
- showGoBack,
- progressAnimation
- });
- }
- }
- return Promise.resolve(false);
- }
-
- private async wait(task: () => Promise): Promise {
- if (this.runningTask !== undefined) {
- await this.runningTask;
- this.runningTask = undefined;
- }
- const promise = this.runningTask = task();
- return promise;
- }
-}
-
-const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
- if (typeof (requestAnimationFrame as any) === 'function') {
- return new Promise(resolve => {
- requestAnimationFrame(() => {
- cleanup(activeRoute, views, viewsSnapshot, location);
- resolve();
- });
- });
- }
- return Promise.resolve();
-};
-
-const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
- viewsSnapshot
- .filter(view => !views.includes(view))
- .forEach(destroyView);
-
- views.forEach(view => {
- /**
- * In the event that a user navigated multiple
- * times in rapid succession, we want to make sure
- * we don't pre-emptively detach a view while
- * it is in mid-transition.
- *
- * In this instance we also do not care about query
- * params or fragments as it will be the same view regardless
- */
- const locationWithoutParams = location.path().split('?')[0];
- const locationWithoutFragment = locationWithoutParams.split('#')[0];
-
- if (view !== activeRoute && view.url !== locationWithoutFragment) {
- const element = view.element;
- element.setAttribute('aria-hidden', 'true');
- element.classList.add('ion-page-hidden');
- view.ref.changeDetectorRef.detach();
- }
- });
-};
diff --git a/angular/src/directives/navigation/stack-utils.ts b/angular/src/directives/navigation/stack-utils.ts
deleted file mode 100644
index b6ab21c24ab..00000000000
--- a/angular/src/directives/navigation/stack-utils.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { ComponentRef } from '@angular/core';
-import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
-import { NavDirection, RouterDirection } from '@ionic/core';
-
-export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
- if (direction === 'root') {
- return setRoot(views, view);
- } else if (direction === 'forward') {
- return setForward(views, view);
- } else {
- return setBack(views, view);
- }
-};
-
-const setRoot = (views: RouteView[], view: RouteView) => {
- views = views.filter(v => v.stackId !== view.stackId);
- views.push(view);
- return views;
-};
-
-const setForward = (views: RouteView[], view: RouteView) => {
- const index = views.indexOf(view);
- if (index >= 0) {
- views = views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
- } else {
- views.push(view);
- }
- return views;
-};
-
-const setBack = (views: RouteView[], view: RouteView) => {
- const index = views.indexOf(view);
- if (index >= 0) {
- return views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
- } else {
- return setRoot(views, view);
- }
-};
-
-export const getUrl = (router: Router, activatedRoute: ActivatedRoute) => {
- const urlTree = router.createUrlTree(['.'], { relativeTo: activatedRoute });
- return router.serializeUrl(urlTree);
-};
-
-export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined) => {
- if (!leavingView) {
- return true;
- }
- return enteringView.stackId !== leavingView.stackId;
-};
-
-export const computeStackId = (prefixUrl: string[] | undefined, url: string) => {
- if (!prefixUrl) {
- return undefined;
- }
- const segments = toSegments(url);
- for (let i = 0; i < segments.length; i++) {
- if (i >= prefixUrl.length) {
- return segments[i];
- }
- if (segments[i] !== prefixUrl[i]) {
- return undefined;
- }
- }
- return undefined;
-};
-
-export const toSegments = (path: string) => {
- return path
- .split('/')
- .map(s => s.trim())
- .filter(s => s !== '');
-};
-
-export const destroyView = (view: RouteView | undefined) => {
- if (view) {
- // TODO lifecycle event
- view.ref.destroy();
- view.unlistenEvents();
- }
-};
-
-export interface StackEvent {
- enteringView: RouteView;
- direction: RouterDirection;
- animation: NavDirection | undefined;
- tabSwitch: boolean;
-}
-
-export interface RouteView {
- id: number;
- url: string;
- stackId: string | undefined;
- element: HTMLElement;
- ref: ComponentRef;
- savedData?: any;
- savedExtras?: NavigationExtras;
- unlistenEvents: () => void;
-}
diff --git a/angular/src/directives/proxies-list.txt b/angular/src/directives/proxies-list.txt
deleted file mode 100644
index 0c4ca502be2..00000000000
--- a/angular/src/directives/proxies-list.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-
-import * as d from './proxies';
-
-export const DIRECTIVES = [
- d.IonApp,
- d.IonAvatar,
- d.IonBackButton,
- d.IonBackdrop,
- d.IonBadge,
- d.IonButton,
- d.IonButtons,
- d.IonCard,
- d.IonCardContent,
- d.IonCardHeader,
- d.IonCardSubtitle,
- d.IonCardTitle,
- d.IonCheckbox,
- d.IonChip,
- d.IonCol,
- d.IonContent,
- d.IonDatetime,
- d.IonFab,
- d.IonFabButton,
- d.IonFabList,
- d.IonFooter,
- d.IonGrid,
- d.IonHeader,
- d.IonIcon,
- d.IonImg,
- d.IonInfiniteScroll,
- d.IonInfiniteScrollContent,
- d.IonInput,
- d.IonItem,
- d.IonItemDivider,
- d.IonItemGroup,
- d.IonItemOption,
- d.IonItemOptions,
- d.IonItemSliding,
- d.IonLabel,
- d.IonList,
- d.IonListHeader,
- d.IonMenu,
- d.IonMenuButton,
- d.IonMenuToggle,
- d.IonNav,
- d.IonNavLink,
- d.IonNote,
- d.IonProgressBar,
- d.IonRadio,
- d.IonRadioGroup,
- d.IonRange,
- d.IonRefresher,
- d.IonRefresherContent,
- d.IonReorder,
- d.IonReorderGroup,
- d.IonRippleEffect,
- d.IonRow,
- d.IonSearchbar,
- d.IonSegment,
- d.IonSegmentButton,
- d.IonSelect,
- d.IonSelectOption,
- d.IonSkeletonText,
- d.IonSlide,
- d.IonSlides,
- d.IonSpinner,
- d.IonSplitPane,
- d.IonTabBar,
- d.IonTabButton,
- d.IonText,
- d.IonTextarea,
- d.IonThumbnail,
- d.IonTitle,
- d.IonToggle,
- d.IonToolbar
-];
diff --git a/angular/src/directives/proxies-utils.ts b/angular/src/directives/proxies-utils.ts
deleted file mode 100644
index c1f72601f43..00000000000
--- a/angular/src/directives/proxies-utils.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/* eslint-disable */
-/* tslint:disable */
-import { fromEvent } from 'rxjs';
-
-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));
- }
- });
- });
-};
-
-export const proxyMethods = (Cmp: any, methods: string[]) => {
- const Prototype = Cmp.prototype;
- methods.forEach(methodName => {
- Prototype[methodName] = function () {
- const args = arguments;
- 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));
-}
-
-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
deleted file mode 100644
index d1ca187a0ca..00000000000
--- a/angular/src/directives/proxies.ts
+++ /dev/null
@@ -1,881 +0,0 @@
-/* eslint-disable */
-/* tslint:disable */
-/* auto-generated angular directive proxies */
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, NgZone } from "@angular/core";
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonAvatar extends Components.IonAvatar {
-}
-@Component({ selector: "ion-avatar", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonAvatar {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionBackdropTap"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionFocus", "ionBlur"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange", "ionFocus", "ionBlur"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionScroll!: EventEmitter;
- ionScrollEnd!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionScrollStart", "ionScroll", "ionScrollEnd"]);
- }
-}
-export declare interface IonDatetime extends Components.IonDatetime {
-}
-@ProxyCmp({ inputs: ["cancelText", "dayNames", "dayShortNames", "dayValues", "disabled", "displayFormat", "displayTimezone", "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", "displayTimezone", "doneText", "hourValues", "max", "min", "minuteValues", "mode", "monthNames", "monthShortNames", "monthValues", "name", "pickerFormat", "pickerOptions", "placeholder", "readonly", "value", "yearValues"] })
-export class IonDatetime {
- ionCancel!: EventEmitter;
- ionChange!: EventEmitter;
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionCancel", "ionChange", "ionFocus", "ionBlur"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionFocus", "ionBlur"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionImgDidLoad!: EventEmitter;
- ionError!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionImgWillLoad", "ionImgDidLoad", "ionError"]);
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionInfinite"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonInput extends Components.IonInput {
-}
-@ProxyCmp({ inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "debounce", "disabled", "enterkeyhint", "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", "enterkeyhint", "inputmode", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "size", "spellcheck", "step", "type", "value"] })
-export class IonInput {
- ionInput!: EventEmitter;
- ionChange!: EventEmitter;
- ionBlur!: EventEmitter;
- ionFocus!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionInput", "ionChange", "ionBlur", "ionFocus"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonItemGroup extends Components.IonItemGroup {
-}
-@Component({ selector: "ion-item-group", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonItemGroup {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionSwipe"]);
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionDrag"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionWillClose!: EventEmitter;
- ionDidOpen!: EventEmitter;
- ionDidClose!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionWillOpen", "ionWillClose", "ionDidOpen", "ionDidClose"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionNavDidChange!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionNavWillChange", "ionNavDidChange"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonRadio extends Components.IonRadio {
-}
-@ProxyCmp({ inputs: ["color", "disabled", "mode", "name", "value"] })
-@Component({ selector: "ion-radio", changeDetection: ChangeDetectionStrategy.OnPush, template: " ", inputs: ["color", "disabled", "mode", "name", "value"] })
-export class IonRadio {
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionFocus", "ionBlur"]);
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange"]);
- }
-}
-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;
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange", "ionFocus", "ionBlur"]);
- }
-}
-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;
- ionPull!: EventEmitter;
- ionStart!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionRefresh", "ionPull", "ionStart"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonReorder extends Components.IonReorder {
-}
-@Component({ selector: "ion-reorder", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonReorder {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionItemReorder"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonRow extends Components.IonRow {
-}
-@Component({ selector: "ion-row", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonRow {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonSearchbar extends Components.IonSearchbar {
-}
-@ProxyCmp({ inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "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", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "spellcheck", "type", "value"] })
-export class IonSearchbar {
- ionInput!: EventEmitter;
- ionChange!: EventEmitter;
- ionCancel!: EventEmitter;
- ionClear!: EventEmitter;
- ionBlur!: EventEmitter;
- ionFocus!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionInput", "ionChange", "ionCancel", "ionClear", "ionBlur", "ionFocus"]);
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange"]);
- }
-}
-export declare interface IonSegmentButton extends Components.IonSegmentButton {
-}
-@ProxyCmp({ inputs: ["disabled", "layout", "mode", "type", "value"] })
-@Component({ selector: "ion-segment-button", changeDetection: ChangeDetectionStrategy.OnPush, template: " ", inputs: ["disabled", "layout", "mode", "type", "value"] })
-export class IonSegmentButton {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionCancel!: EventEmitter;
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange", "ionCancel", "ionFocus", "ionBlur"]);
- }
-}
-export declare interface IonSelectOption extends Components.IonSelectOption {
-}
-@ProxyCmp({ inputs: ["disabled", "value"] })
-@Component({ selector: "ion-select-option", changeDetection: ChangeDetectionStrategy.OnPush, template: " ", inputs: ["disabled", "value"] })
-export class IonSelectOption {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonSlide extends Components.IonSlide {
-}
-@Component({ selector: "ion-slide", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonSlide {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionSlideTap!: EventEmitter;
- ionSlideDoubleTap!: EventEmitter;
- ionSlideWillChange!: EventEmitter;
- ionSlideDidChange!: EventEmitter;
- ionSlideNextStart!: EventEmitter;
- ionSlidePrevStart!: EventEmitter;
- ionSlideNextEnd!: EventEmitter;
- ionSlidePrevEnd!: EventEmitter;
- ionSlideTransitionStart!: EventEmitter;
- ionSlideTransitionEnd!: EventEmitter;
- ionSlideDrag!: EventEmitter;
- ionSlideReachStart!: EventEmitter;
- ionSlideReachEnd!: EventEmitter;
- ionSlideTouchStart!: EventEmitter;
- ionSlideTouchEnd!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionSlidesDidLoad", "ionSlideTap", "ionSlideDoubleTap", "ionSlideWillChange", "ionSlideDidChange", "ionSlideNextStart", "ionSlidePrevStart", "ionSlideNextEnd", "ionSlidePrevEnd", "ionSlideTransitionStart", "ionSlideTransitionEnd", "ionSlideDrag", "ionSlideReachStart", "ionSlideReachEnd", "ionSlideTouchStart", "ionSlideTouchEnd"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionSplitPaneVisible"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-export declare interface IonTextarea extends Components.IonTextarea {
-}
-@ProxyCmp({ inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "debounce", "disabled", "enterkeyhint", "inputmode", "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", "enterkeyhint", "inputmode", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "spellcheck", "value", "wrap"] })
-export class IonTextarea {
- ionChange!: EventEmitter;
- ionInput!: EventEmitter;
- ionBlur!: EventEmitter;
- ionFocus!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange", "ionInput", "ionBlur", "ionFocus"]);
- }
-}
-export declare interface IonThumbnail extends Components.IonThumbnail {
-}
-@Component({ selector: "ion-thumbnail", changeDetection: ChangeDetectionStrategy.OnPush, template: " " })
-export class IonThumbnail {
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
-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;
- ionFocus!: EventEmitter;
- ionBlur!: EventEmitter;
- protected el: HTMLElement;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- proxyOutputs(this, this.el, ["ionChange", "ionFocus", "ionBlur"]);
- }
-}
-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;
- constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
- c.detach();
- this.el = r.nativeElement;
- }
-}
diff --git a/angular/src/directives/virtual-scroll/virtual-footer.ts b/angular/src/directives/virtual-scroll/virtual-footer.ts
deleted file mode 100644
index 3c42173754c..00000000000
--- a/angular/src/directives/virtual-scroll/virtual-footer.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Directive, TemplateRef } from '@angular/core';
-
-import { VirtualContext } from './virtual-utils';
-
-/**
- * @hidden
- */
-@Directive({ selector: '[virtualFooter]' })
-export class VirtualFooter {
- constructor(public templateRef: TemplateRef) {}
-}
diff --git a/angular/src/directives/virtual-scroll/virtual-header.ts b/angular/src/directives/virtual-scroll/virtual-header.ts
deleted file mode 100644
index a4f519efe72..00000000000
--- a/angular/src/directives/virtual-scroll/virtual-header.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Directive, TemplateRef } from '@angular/core';
-
-import { VirtualContext } from './virtual-utils';
-
-/**
- * @hidden
- */
-@Directive({ selector: '[virtualHeader]' })
-export class VirtualHeader {
- constructor(public templateRef: TemplateRef) {}
-}
diff --git a/angular/src/directives/virtual-scroll/virtual-item.ts b/angular/src/directives/virtual-scroll/virtual-item.ts
deleted file mode 100644
index 93056d34eae..00000000000
--- a/angular/src/directives/virtual-scroll/virtual-item.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';
-
-import { VirtualContext } from './virtual-utils';
-
-/**
- * @hidden
- */
-@Directive({ selector: '[virtualItem]' })
-export class VirtualItem {
- constructor(public templateRef: TemplateRef, public viewContainer: ViewContainerRef) {}
-}
diff --git a/angular/src/directives/virtual-scroll/virtual-scroll.ts b/angular/src/directives/virtual-scroll/virtual-scroll.ts
deleted file mode 100644
index b28f55bd769..00000000000
--- a/angular/src/directives/virtual-scroll/virtual-scroll.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-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 { ProxyCmp } from '../proxies-utils';
-
-import { VirtualFooter } from './virtual-footer';
-import { VirtualHeader } from './virtual-header';
-import { VirtualItem } from './virtual-item';
-import { VirtualContext } from './virtual-utils';
-
-export declare interface IonVirtualScroll {
- /**
- * It is important to provide this
- * if virtual item height will be significantly larger than the default
- * The approximate height of each virtual item template's cell.
- * This dimension is used to help determine how many cells should
- * be created when initialized, and to help calculate the height of
- * the scrollable area. This height value can only use `px` units.
- * Note that the actual rendered size of each cell comes from the
- * app's CSS, whereas this approximation is used to help calculate
- * initial dimensions before the item has been rendered.
- */
- approxItemHeight: number;
-
- /**
- * The approximate height of each header template's cell.
- * This dimension is used to help determine how many cells should
- * be created when initialized, and to help calculate the height of
- * the scrollable area. This height value can only use `px` units.
- * Note that the actual rendered size of each cell comes from the
- * app's CSS, whereas this approximation is used to help calculate
- * initial dimensions before the item has been rendered.
- */
- approxHeaderHeight: number;
-
- /**
- * The approximate width of each footer template's cell.
- * This dimension is used to help determine how many cells should
- * be created when initialized, and to help calculate the height of
- * the scrollable area. This height value can only use `px` units.
- * Note that the actual rendered size of each cell comes from the
- * app's CSS, whereas this approximation is used to help calculate
- * initial dimensions before the item has been rendered.
- */
- approxFooterHeight: number;
-
- /**
- * Section headers and the data used within its given
- * template can be dynamically created by passing a function to `headerFn`.
- * For example, a large list of contacts usually has dividers between each
- * letter in the alphabet. App's can provide their own custom `headerFn`
- * which is called with each record within the dataset. The logic within
- * the header function can decide if the header template should be used,
- * and what data to give to the header template. The function must return
- * `null` if a header cell shouldn't be created.
- */
- headerFn?: HeaderFn;
-
- /**
- * Section footers and the data used within its given
- * template can be dynamically created by passing a function to `footerFn`.
- * The logic within the footer function can decide if the footer template
- * should be used, and what data to give to the footer template. The function
- * must return `null` if a footer cell shouldn't be created.
- */
- footerFn?: HeaderFn;
-
- /**
- * The data that builds the templates within the virtual scroll.
- * It's important to note that when this data has changed, then the
- * entire virtual scroll is reset, which is an expensive operation and
- * should be avoided if possible.
- */
- items?: any[];
-
- /**
- * An optional function that maps each item within their height.
- * When this function is provided, heavy optimizations and fast path can be taked by
- * `ion-virtual-scroll` leading to massive performance improvements.
- *
- * This function allows to skip all DOM reads, which can be Doing so leads
- * to massive performance
- */
- itemHeight?: ItemHeightFn;
-
- /**
- * An optional function that maps each item header within their height.
- */
- headerHeight?: HeaderHeightFn;
-
- /**
- * An optional function that maps each item footer within their height.
- */
- footerHeight?: FooterHeightFn;
-
- /**
- * Same as `ngForTrackBy` which can be used on `ngFor`.
- */
- trackBy: TrackByFunction;
-
- /**
- * This method marks the tail the items array as dirty, so they can be re-rendered. It's equivalent to calling: ```js * virtualScroll.checkRange(lastItemLen, items.length - lastItemLen); * ```
- */
- 'checkEnd': () => void;
- /**
- * This method marks a subset of items as dirty, so they can be re-rendered. Items should be marked as dirty any time the content or their style changes. The subset of items to be updated can are specifing by an offset and a length.
- */
- 'checkRange': (offset: number, len?: number) => void;
- /**
- * Returns the position of the virtual item at the given index.
- */
- '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: ' ',
- changeDetection: ChangeDetectionStrategy.OnPush,
- inputs: [
- 'approxItemHeight',
- 'approxHeaderHeight',
- 'approxFooterHeight',
- 'headerFn',
- 'footerFn',
- 'items',
- 'itemHeight',
- 'headerHeight',
- 'footerHeight',
- 'trackBy'
- ]
-})
-export class IonVirtualScroll {
-
- private differ?: IterableDiffer;
- private el: HTMLIonVirtualScrollElement;
- private refMap = new WeakMap>();
-
- @ContentChild(VirtualItem, { static: false }) itmTmp!: VirtualItem;
- @ContentChild(VirtualHeader, { static: false }) hdrTmp!: VirtualHeader;
- @ContentChild(VirtualFooter, { static: false }) ftrTmp!: VirtualFooter;
-
- constructor(
- private z: NgZone,
- private iterableDiffers: IterableDiffers,
- elementRef: ElementRef,
- ) {
- this.el = elementRef.nativeElement as HTMLIonVirtualScrollElement;
- this.el.nodeRender = this.nodeRender.bind(this);
- }
-
- ngOnChanges(changes: SimpleChanges): void {
- if (this.trackBy && 'items' in changes) {
- // React on virtualScroll changes only once all inputs have been initialized
- const value = changes['items'].currentValue;
- if (this.differ === undefined && value != null) {
- try {
- this.differ = this.iterableDiffers.find(value).create(this.trackBy);
- } catch (e) {
- throw new Error(
- `Cannot find a differ supporting object '${value}'. VirtualScroll only supports binding to Iterables such as Arrays.`);
- }
- }
- }
- }
-
- ngDoCheck() {
- // and if there actually are changes
- const changes = this.differ !== undefined && this.items ? this.differ.diff(this.items) : null;
- if (changes === null) {
- return;
- }
- // TODO: optimize
- this.checkRange(0);
- }
-
- private nodeRender(el: HTMLElement | null, cell: Cell, index: number): HTMLElement {
- return this.z.run(() => {
- let node: EmbeddedViewRef;
- if (!el) {
- node = this.itmTmp.viewContainer.createEmbeddedView(
- this.getComponent(cell.type),
- { $implicit: cell.value, index },
- index
- );
- el = getElement(node);
- this.refMap.set(el, node);
- } else {
- node = this.refMap.get(el)!;
- const ctx = node.context;
- ctx.$implicit = cell.value;
- ctx.index = cell.index;
- }
- // run sync change detections
- node.detectChanges();
- return el;
- });
- }
-
- private getComponent(type: CellType) {
- switch (type) {
- case 'item': return this.itmTmp.templateRef;
- case 'header': return this.hdrTmp.templateRef;
- case 'footer': return this.ftrTmp.templateRef;
- }
- throw new Error('template for virtual item was not provided');
- }
-}
-
-const getElement = (view: EmbeddedViewRef): HTMLElement => {
- const rootNodes = view.rootNodes;
- for (let i = 0; i < rootNodes.length; i++) {
- if (rootNodes[i].nodeType === 1) {
- return rootNodes[i];
- }
- }
- throw new Error('virtual element was not created');
-};
diff --git a/angular/src/directives/virtual-scroll/virtual-utils.ts b/angular/src/directives/virtual-scroll/virtual-utils.ts
deleted file mode 100644
index fc6336844f0..00000000000
--- a/angular/src/directives/virtual-scroll/virtual-utils.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-
-export interface VirtualContext {
- $implicit: any;
- index: number;
-}
diff --git a/angular/src/index.ts b/angular/src/index.ts
deleted file mode 100644
index 46de9c00127..00000000000
--- a/angular/src/index.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// DIRECTIVES
-export { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
-export { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
-export { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
-export { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
-export { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
-export { IonTabs } from './directives/navigation/ion-tabs';
-export { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
-export { NavDelegate } from './directives/navigation/nav-delegate';
-export { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
-export { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
-export { NavParams } from './directives/navigation/nav-params';
-export { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
-export { VirtualItem } from './directives/virtual-scroll/virtual-item';
-export { VirtualHeader } from './directives/virtual-scroll/virtual-header';
-export { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
-export * from './directives/proxies';
-
-// PROVIDERS
-export { AngularDelegate } from './providers/angular-delegate';
-export { ActionSheetController } from './providers/action-sheet-controller';
-export { AlertController } from './providers/alert-controller';
-export { LoadingController } from './providers/loading-controller';
-export { MenuController } from './providers/menu-controller';
-export { PickerController } from './providers/picker-controller';
-export { ModalController } from './providers/modal-controller';
-export { Platform } from './providers/platform';
-export { PopoverController } from './providers/popover-controller';
-export { ToastController } from './providers/toast-controller';
-export { NavController } from './providers/nav-controller';
-export { DomController } from './providers/dom-controller';
-export { Config } from './providers/config';
-export { AnimationController } from './providers/animation-controller';
-export { GestureController } from './providers/gesture-controller';
-
-// ROUTER STRATEGY
-export { IonicRouteStrategy } from './util/ionic-router-reuse-strategy';
-
-// PACKAGE MODULE
-export { IonicModule } from './ionic-module';
-
-// UTILS
-export { IonicSafeString } from '@ionic/core';
-
-// CORE TYPES
-export { Animation, AnimationBuilder, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, Gesture, GestureConfig, GestureDetail, mdTransitionAnimation, iosTransitionAnimation } from '@ionic/core';
diff --git a/angular/src/ionic-module.ts b/angular/src/ionic-module.ts
deleted file mode 100644
index a3ea4a8fb7c..00000000000
--- a/angular/src/ionic-module.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import { CommonModule, DOCUMENT } from '@angular/common';
-import { APP_INITIALIZER, ModuleWithProviders, NgModule, NgZone } from '@angular/core';
-import { IonicConfig } from '@ionic/core';
-
-import { appInitialize } from './app-initialize';
-import { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
-import { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
-import { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
-import { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
-import { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
-import { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
-import { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
-import { IonTabs } from './directives/navigation/ion-tabs';
-import { NavDelegate } from './directives/navigation/nav-delegate';
-import { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
-import { IonApp, IonAvatar, IonBackButton, IonBackdrop, IonBadge, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInfiniteScrollContent, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonListHeader, IonMenu, IonMenuButton, IonMenuToggle, IonNav, IonNavLink, IonNote, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTabBar, IonTabButton, IonText, IonTextarea, IonThumbnail, IonTitle, IonToggle, IonToolbar } from './directives/proxies';
-import { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
-import { VirtualHeader } from './directives/virtual-scroll/virtual-header';
-import { VirtualItem } from './directives/virtual-scroll/virtual-item';
-import { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
-import { AngularDelegate } from './providers/angular-delegate';
-import { ConfigToken } from './providers/config';
-import { ModalController } from './providers/modal-controller';
-import { PopoverController } from './providers/popover-controller';
-
-const DECLARATIONS = [
- // proxies
- IonApp,
- IonAvatar,
- IonBackButton,
- IonBackdrop,
- IonBadge,
- IonButton,
- IonButtons,
- IonCard,
- IonCardContent,
- IonCardHeader,
- IonCardSubtitle,
- IonCardTitle,
- IonCheckbox,
- IonChip,
- IonCol,
- IonContent,
- IonDatetime,
- IonFab,
- IonFabButton,
- IonFabList,
- IonFooter,
- IonGrid,
- IonHeader,
- IonIcon,
- IonImg,
- IonInfiniteScroll,
- IonInfiniteScrollContent,
- IonInput,
- IonItem,
- IonItemDivider,
- IonItemGroup,
- IonItemOption,
- IonItemOptions,
- IonItemSliding,
- IonLabel,
- IonList,
- IonListHeader,
- IonMenu,
- IonMenuButton,
- IonMenuToggle,
- IonNav,
- IonNavLink,
- IonNote,
- IonProgressBar,
- IonRadio,
- IonRadioGroup,
- IonRange,
- IonRefresher,
- IonRefresherContent,
- IonReorder,
- IonReorderGroup,
- IonRippleEffect,
- IonRow,
- IonSearchbar,
- IonSegment,
- IonSegmentButton,
- IonSelect,
- IonSelectOption,
- IonSkeletonText,
- IonSlide,
- IonSlides,
- IonSpinner,
- IonSplitPane,
- IonTabBar,
- IonTabButton,
- IonText,
- IonTextarea,
- IonThumbnail,
- IonToggle,
- IonToolbar,
- IonTitle,
-
- IonTabs,
-
- // ngModel accessors
- BooleanValueAccessor,
- NumericValueAccessor,
- RadioValueAccessor,
- SelectValueAccessor,
- TextValueAccessor,
-
- // navigation
- IonRouterOutlet,
- IonBackButtonDelegate,
- NavDelegate,
- RouterLinkDelegate,
-
- // virtual scroll
- VirtualFooter,
- VirtualHeader,
- VirtualItem,
- IonVirtualScroll
-];
-
-@NgModule({
- declarations: DECLARATIONS,
- exports: DECLARATIONS,
- providers: [AngularDelegate, ModalController, PopoverController],
- imports: [CommonModule]
-})
-export class IonicModule {
- static forRoot(config?: IonicConfig): ModuleWithProviders {
- return {
- ngModule: IonicModule,
- providers: [
- {
- provide: ConfigToken,
- useValue: config
- },
- {
- provide: APP_INITIALIZER,
- useFactory: appInitialize,
- multi: true,
- deps: [
- ConfigToken,
- DOCUMENT,
- NgZone
- ]
- }
- ]
- };
- }
-}
diff --git a/angular/src/providers/action-sheet-controller.ts b/angular/src/providers/action-sheet-controller.ts
deleted file mode 100644
index d2c92bd8e0e..00000000000
--- a/angular/src/providers/action-sheet-controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core';
-import { ActionSheetOptions, actionSheetController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-@Injectable({
- providedIn: 'root',
-})
-export class ActionSheetController extends OverlayBaseController {
- constructor() {
- super(actionSheetController);
- }
-}
diff --git a/angular/src/providers/alert-controller.ts b/angular/src/providers/alert-controller.ts
deleted file mode 100644
index abffc7577cb..00000000000
--- a/angular/src/providers/alert-controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core';
-import { AlertOptions, alertController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-@Injectable({
- providedIn: 'root',
-})
-export class AlertController extends OverlayBaseController {
- constructor() {
- super(alertController);
- }
-}
diff --git a/angular/src/providers/angular-delegate.ts b/angular/src/providers/angular-delegate.ts
deleted file mode 100644
index 5f0912d10b1..00000000000
--- a/angular/src/providers/angular-delegate.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
-import { FrameworkDelegate, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from '@ionic/core';
-
-import { NavParams } from '../directives/navigation/nav-params';
-
-@Injectable()
-export class AngularDelegate {
-
- constructor(
- private zone: NgZone,
- private appRef: ApplicationRef
- ) {}
-
- create(
- resolver: ComponentFactoryResolver,
- injector: Injector,
- location?: ViewContainerRef,
- ) {
- return new AngularFrameworkDelegate(resolver, injector, location, this.appRef, this.zone);
- }
-}
-
-export class AngularFrameworkDelegate implements FrameworkDelegate {
-
- private elRefMap = new WeakMap();
- private elEventsMap = new WeakMap void>();
-
- constructor(
- private resolver: ComponentFactoryResolver,
- private injector: Injector,
- private location: ViewContainerRef | undefined,
- private appRef: ApplicationRef,
- private zone: NgZone,
- ) {}
-
- attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise {
- return this.zone.run(() => {
- return new Promise(resolve => {
- const el = attachView(
- this.zone, this.resolver, this.injector, this.location, this.appRef,
- this.elRefMap, this.elEventsMap,
- container, component, params, cssClasses
- );
- resolve(el);
- });
- });
- }
-
- removeViewFromDom(_container: any, component: any): Promise {
- return this.zone.run(() => {
- return new Promise(resolve => {
- const componentRef = this.elRefMap.get(component);
- if (componentRef) {
- componentRef.destroy();
- this.elRefMap.delete(component);
- const unbindEvents = this.elEventsMap.get(component);
- if (unbindEvents) {
- unbindEvents();
- this.elEventsMap.delete(component);
- }
- }
- resolve();
- });
- });
- }
-}
-
-export const attachView = (
- zone: NgZone,
- resolver: ComponentFactoryResolver,
- injector: Injector,
- location: ViewContainerRef | undefined,
- appRef: ApplicationRef,
- elRefMap: WeakMap,
- elEventsMap: WeakMap void>,
- container: any, component: any, params: any, cssClasses: string[] | undefined
-) => {
- const factory = resolver.resolveComponentFactory(component);
- const childInjector = Injector.create({
- providers: getProviders(params),
- parent: injector
- });
- const componentRef = (location)
- ? location.createComponent(factory, location.length, childInjector)
- : factory.create(childInjector);
-
- const instance = componentRef.instance;
- const hostElement = componentRef.location.nativeElement;
- if (params) {
- Object.assign(instance, params);
- }
- if (cssClasses) {
- for (const clazz of cssClasses) {
- hostElement.classList.add(clazz);
- }
- }
- const unbindEvents = bindLifecycleEvents(zone, instance, hostElement);
- container.appendChild(hostElement);
-
- if (!location) {
- appRef.attachView(componentRef.hostView);
- }
- componentRef.changeDetectorRef.reattach();
- elRefMap.set(hostElement, componentRef);
- elEventsMap.set(hostElement, unbindEvents);
- return hostElement;
-};
-
-const LIFECYCLES = [
- LIFECYCLE_WILL_ENTER,
- LIFECYCLE_DID_ENTER,
- LIFECYCLE_WILL_LEAVE,
- LIFECYCLE_DID_LEAVE,
- LIFECYCLE_WILL_UNLOAD
-];
-
-export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
- return zone.run(() => {
- const unregisters = LIFECYCLES
- .filter(eventName => typeof instance[eventName] === 'function')
- .map(eventName => {
- const handler = (ev: any) => instance[eventName](ev.detail);
- element.addEventListener(eventName, handler);
- return () => element.removeEventListener(eventName, handler);
- });
- return () => unregisters.forEach(fn => fn());
- });
-};
-
-const NavParamsToken = new InjectionToken('NavParamsToken');
-
-const getProviders = (params: {[key: string]: any}) => {
- return [
- {
- provide: NavParamsToken, useValue: params
- },
- {
- provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
- }
- ];
-};
-
-const provideNavParamsInjectable = (params: {[key: string]: any}) => {
- return new NavParams(params);
-};
diff --git a/angular/src/providers/animation-controller.ts b/angular/src/providers/animation-controller.ts
deleted file mode 100644
index abd620c5712..00000000000
--- a/angular/src/providers/animation-controller.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Animation, createAnimation, getTimeGivenProgression } from '@ionic/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class AnimationController {
- /**
- * Create a new animation
- */
- create(animationId?: string): Animation {
- return createAnimation(animationId);
- }
-
- /**
- * EXPERIMENTAL
- *
- * Given a progression and a cubic bezier function,
- * this utility returns the time value(s) at which the
- * cubic bezier reaches the given time progression.
- *
- * If the cubic bezier never reaches the progression
- * the result will be an empty array.
- *
- * This is most useful for switching between easing curves
- * when doing a gesture animation (i.e. going from linear easing
- * during a drag, to another easing when `progressEnd` is called)
- */
- easingTime(p0: number[], p1: number[], p2: number[], p3: number[], progression: number): number[] {
- return getTimeGivenProgression(p0, p1, p2, p3, progression);
- }
-}
diff --git a/angular/src/providers/config.ts b/angular/src/providers/config.ts
deleted file mode 100644
index c51c0a6c40e..00000000000
--- a/angular/src/providers/config.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Injectable, InjectionToken } from '@angular/core';
-import { Config as CoreConfig, IonicConfig } from '@ionic/core';
-
-import { IonicWindow } from '../types/interfaces';
-
-@Injectable({
- providedIn: 'root'
-})
-export class Config {
-
- get(key: keyof IonicConfig, fallback?: any): any {
- const c = getConfig();
- if (c) {
- return c.get(key, fallback);
- }
- return null;
- }
-
- getBoolean(key: keyof IonicConfig, fallback?: boolean): boolean {
- const c = getConfig();
- if (c) {
- return c.getBoolean(key, fallback);
- }
- return false;
- }
-
- getNumber(key: keyof IonicConfig, fallback?: number): number {
- const c = getConfig();
- if (c) {
- return c.getNumber(key, fallback);
- }
- return 0;
- }
-
- set(key: keyof IonicConfig, value?: any) {
- console.warn(`[DEPRECATION][Config]: The Config.set() method is deprecated and will be removed in Ionic Framework 6.0. Please see https://ionicframework.com/docs/angular/config for alternatives.`);
- const c = getConfig();
- if (c) {
- c.set(key, value);
- }
- }
-}
-
-export const ConfigToken = new InjectionToken('USERCONFIG');
-
-const getConfig = (): CoreConfig | null => {
- if (typeof (window as any) !== 'undefined') {
- const Ionic = (window as any as IonicWindow).Ionic;
- if (Ionic && Ionic.config) {
- return Ionic.config;
- }
- }
- return null;
-};
diff --git a/angular/src/providers/gesture-controller.ts b/angular/src/providers/gesture-controller.ts
deleted file mode 100644
index 748f65154e2..00000000000
--- a/angular/src/providers/gesture-controller.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Injectable, NgZone } from '@angular/core';
-import { Gesture, GestureConfig, createGesture } from '@ionic/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class GestureController {
- constructor(private zone: NgZone) {}
- /**
- * Create a new gesture
- */
- create(opts: GestureConfig, runInsideAngularZone = false): Gesture {
- if (runInsideAngularZone) {
- Object.getOwnPropertyNames(opts).forEach(key => {
- if (typeof opts[key] === 'function') {
- const fn = opts[key];
- opts[key] = (...props) => this.zone.run(() => fn(...props));
- }
- });
- }
-
- return createGesture(opts);
- }
-}
diff --git a/angular/src/providers/loading-controller.ts b/angular/src/providers/loading-controller.ts
deleted file mode 100644
index a132949ccc1..00000000000
--- a/angular/src/providers/loading-controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core';
-import { LoadingOptions, loadingController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-@Injectable({
- providedIn: 'root',
-})
-export class LoadingController extends OverlayBaseController {
- constructor() {
- super(loadingController);
- }
-}
diff --git a/angular/src/providers/menu-controller.ts b/angular/src/providers/menu-controller.ts
deleted file mode 100644
index f8bc60fc378..00000000000
--- a/angular/src/providers/menu-controller.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import { Injectable } from '@angular/core';
-import { menuController } from '@ionic/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class MenuController {
-
- /**
- * Programmatically open the Menu.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return returns a promise when the menu is fully opened
- */
- open(menuId?: string) {
- return menuController.open(menuId);
- }
-
- /**
- * Programmatically close the Menu. If no `menuId` is given as the first
- * argument then it'll close any menu which is open. If a `menuId`
- * is given then it'll close that exact menu.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return returns a promise when the menu is fully closed
- */
- close(menuId?: string) {
- return menuController.close(menuId);
- }
-
- /**
- * Toggle the menu. If it's closed, it will open, and if opened, it
- * will close.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return returns a promise when the menu has been toggled
- */
- toggle(menuId?: string) {
- return menuController.toggle(menuId);
- }
-
- /**
- * Used to enable or disable a menu. For example, there could be multiple
- * left menus, but only one of them should be able to be opened at the same
- * time. If there are multiple menus on the same side, then enabling one menu
- * will also automatically disable all the others that are on the same side.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return Returns the instance of the menu, which is useful for chaining.
- */
- enable(shouldEnable: boolean, menuId?: string) {
- return menuController.enable(shouldEnable, menuId);
- }
-
- /**
- * Used to enable or disable the ability to swipe open the menu.
- * @param shouldEnable True if it should be swipe-able, false if not.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return Returns the instance of the menu, which is useful for chaining.
- */
- swipeGesture(shouldEnable: boolean, menuId?: string) {
- return menuController.swipeGesture(shouldEnable, menuId);
- }
-
- /**
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return Returns true if the specified menu is currently open, otherwise false.
- * If the menuId is not specified, it returns true if ANY menu is currenly open.
- */
- isOpen(menuId?: string) {
- return menuController.isOpen(menuId);
- }
-
- /**
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return Returns true if the menu is currently enabled, otherwise false.
- */
- isEnabled(menuId?: string) {
- return menuController.isEnabled(menuId);
- }
-
- /**
- * Used to get a menu instance. If a `menuId` is not provided then it'll
- * return the first menu found. If a `menuId` is `left` or `right`, then
- * it'll return the enabled menu on that side. Otherwise, if a `menuId` is
- * provided, then it'll try to find the menu using the menu's `id`
- * property. If a menu is not found then it'll return `null`.
- * @param [menuId] Optionally get the menu by its id, or side.
- * @return Returns the instance of the menu if found, otherwise `null`.
- */
- get(menuId?: string) {
- return menuController.get(menuId);
- }
-
- /**
- * @return Returns the instance of the menu already opened, otherwise `null`.
- */
- getOpen() {
- return menuController.getOpen();
- }
-
- /**
- * @return Returns an array of all menu instances.
- */
- getMenus() {
- return menuController.getMenus();
- }
-}
diff --git a/angular/src/providers/modal-controller.ts b/angular/src/providers/modal-controller.ts
deleted file mode 100644
index 170d4e1c60f..00000000000
--- a/angular/src/providers/modal-controller.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
-import { ModalOptions, modalController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-import { AngularDelegate } from './angular-delegate';
-
-@Injectable()
-export class ModalController extends OverlayBaseController {
-
- constructor(
- private angularDelegate: AngularDelegate,
- private resolver: ComponentFactoryResolver,
- private injector: Injector,
- ) {
- super(modalController);
- }
-
- create(opts: ModalOptions): Promise {
- return super.create({
- ...opts,
- delegate: this.angularDelegate.create(this.resolver, this.injector)
- });
- }
-}
diff --git a/angular/src/providers/nav-controller.ts b/angular/src/providers/nav-controller.ts
deleted file mode 100644
index a5d8786ea00..00000000000
--- a/angular/src/providers/nav-controller.ts
+++ /dev/null
@@ -1,235 +0,0 @@
-import { Location } from '@angular/common';
-import { Injectable, Optional } from '@angular/core';
-import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
-import { NavDirection, RouterDirection } from '@ionic/core';
-
-import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
-
-import { Platform } from './platform';
-
-export interface AnimationOptions {
- animated?: boolean;
- animationDirection?: 'forward' | 'back';
-}
-
-export interface NavigationOptions extends NavigationExtras, AnimationOptions {}
-
-@Injectable({
- providedIn: 'root',
-})
-export class NavController {
-
- private topOutlet?: IonRouterOutlet;
- private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
- private animated?: NavDirection = DEFAULT_ANIMATED;
- private guessDirection: RouterDirection = 'forward';
- private guessAnimation?: NavDirection;
- private lastNavId = -1;
-
- constructor(
- platform: Platform,
- private location: Location,
- private serializer: UrlSerializer,
- @Optional() private router?: Router,
- ) {
- // Subscribe to router events to detect direction
- if (router) {
- router.events.subscribe(ev => {
- if (ev instanceof NavigationStart) {
- const id = (ev.restoredState) ? ev.restoredState.navigationId : ev.id;
- this.guessDirection = id < this.lastNavId ? 'back' : 'forward';
- this.guessAnimation = !ev.restoredState ? this.guessDirection : undefined;
- this.lastNavId = this.guessDirection === 'forward' ? ev.id : id;
- }
- });
- }
-
- // Subscribe to backButton events
- platform.backButton.subscribeWithPriority(0, processNextHandler => {
- this.pop();
- processNextHandler();
- });
- }
-
- /**
- * This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
- * it's equivalent to calling `this.router.navigateByUrl()`, but it's explicit about the **direction** of the transition.
- *
- * Going **forward** means that a new page is going to be pushed to the stack of the outlet (ion-router-outlet),
- * and that it will show a "forward" animation by default.
- *
- * Navigating forward can also be triggered in a declarative manner by using the `[routerDirection]` directive:
- *
- * ```html
- * Link
- * ```
- */
- navigateForward(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise {
- this.setDirection('forward', options.animated, options.animationDirection);
- return this.navigate(url, options);
- }
-
- /**
- * This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
- * it's equivalent to calling:
- *
- * ```ts
- * this.navController.setDirection('back');
- * this.router.navigateByUrl(path);
- * ```
- *
- * Going **back** means that all the pages in the stack until the navigated page is found will be popped,
- * and that it will show a "back" animation by default.
- *
- * Navigating back can also be triggered in a declarative manner by using the `[routerDirection]` directive:
- *
- * ```html
- * Link
- * ```
- */
- navigateBack(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise {
- this.setDirection('back', options.animated, options.animationDirection);
- return this.navigate(url, options);
- }
-
- /**
- * This method uses Angular's [Router](https://angular.io/api/router/Router) under the hood,
- * it's equivalent to calling:
- *
- * ```ts
- * this.navController.setDirection('root');
- * this.router.navigateByUrl(path);
- * ```
- *
- * Going **root** means that all existing pages in the stack will be removed,
- * and the navigated page will become the single page in the stack.
- *
- * Navigating root can also be triggered in a declarative manner by using the `[routerDirection]` directive:
- *
- * ```html
- * Link
- * ```
- */
- navigateRoot(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise {
- this.setDirection('root', options.animated, options.animationDirection);
- return this.navigate(url, options);
- }
-
- /**
- * Same as [Location](https://angular.io/api/common/Location)'s back() method.
- * It will use the standard `window.history.back()` under the hood, but featuring a `back` animation
- * by default.
- */
- back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
- this.setDirection('back', options.animated, options.animationDirection);
- return this.location.back();
- }
-
- /**
- * This methods goes back in the context of Ionic's stack navigation.
- *
- * It recursively finds the top active `ion-router-outlet` and calls `pop()`.
- * This is the recommended way to go back when you are using `ion-router-outlet`.
- */
- async pop() {
- let outlet = this.topOutlet;
-
- while (outlet) {
- if (await outlet.pop()) {
- break;
- } else {
- outlet = outlet.parentOutlet;
- }
- }
- }
-
- /**
- * This methods specifies the direction of the next navigation performed by the Angular router.
- *
- * `setDirection()` does not trigger any transition, it just sets some flags to be consumed by `ion-router-outlet`.
- *
- * It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
- */
- setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
- this.direction = direction;
- this.animated = getAnimation(direction, animated, animationDirection);
- }
-
- /**
- * @internal
- */
- setTopOutlet(outlet: IonRouterOutlet) {
- this.topOutlet = outlet;
- }
-
- /**
- * @internal
- */
- consumeTransition() {
- let direction: RouterDirection = 'root';
- let animation: NavDirection | undefined;
-
- if (this.direction === 'auto') {
- direction = this.guessDirection;
- animation = this.guessAnimation;
- } else {
- animation = this.animated;
- direction = this.direction;
- }
- this.direction = DEFAULT_DIRECTION;
- this.animated = DEFAULT_ANIMATED;
-
- return {
- direction,
- animation
- };
- }
-
- private navigate(url: string | UrlTree | any[], options: NavigationOptions) {
- if (Array.isArray(url)) {
- return this.router!.navigate(url, options);
- } else {
-
- /**
- * navigateByUrl ignores any properties that
- * would change the url, so things like queryParams
- * would be ignored unless we create a url tree
- * More Info: https://github.com/angular/angular/issues/18798
- */
- const urlTree = this.serializer.parse(url.toString());
-
- if (options.queryParams !== undefined) {
- urlTree.queryParams = { ...options.queryParams };
- }
-
- if (options.fragment !== undefined) {
- urlTree.fragment = options.fragment;
- }
-
- /**
- * `navigateByUrl` will still apply `NavigationExtras` properties
- * that do not modify the url, such as `replaceUrl` which is why
- * `options` is passed in here.
- */
- return this.router!.navigateByUrl(urlTree, options);
- }
- }
-}
-
-const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
- if (animated === false) {
- return undefined;
- }
- if (animationDirection !== undefined) {
- return animationDirection;
- }
- if (direction === 'forward' || direction === 'back') {
- return direction;
- } else if (direction === 'root' && animated === true) {
- return 'forward';
- }
- return undefined;
-};
-
-const DEFAULT_DIRECTION = 'auto';
-const DEFAULT_ANIMATED = undefined;
diff --git a/angular/src/providers/picker-controller.ts b/angular/src/providers/picker-controller.ts
deleted file mode 100644
index a67fb3f7dbf..00000000000
--- a/angular/src/providers/picker-controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core';
-import { PickerOptions, pickerController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-@Injectable({
- providedIn: 'root',
-})
-export class PickerController extends OverlayBaseController {
- constructor() {
- super(pickerController);
- }
-}
diff --git a/angular/src/providers/platform.ts b/angular/src/providers/platform.ts
deleted file mode 100644
index 282b85f196d..00000000000
--- a/angular/src/providers/platform.ts
+++ /dev/null
@@ -1,245 +0,0 @@
-import { DOCUMENT } from '@angular/common';
-import { Inject, Injectable, NgZone } from '@angular/core';
-import { BackButtonEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
-import { Subject, Subscription } from 'rxjs';
-
-export interface BackButtonEmitter extends Subject {
- subscribeWithPriority(priority: number, callback: (processNextHandler: () => void) => Promise | void): Subscription;
-}
-
-@Injectable({
- providedIn: 'root',
-})
-export class Platform {
-
- private _readyPromise: Promise;
- private win: any;
-
- /**
- * @hidden
- */
- backButton: BackButtonEmitter = new Subject() as any;
-
- /**
- * The pause event emits when the native platform puts the application
- * into the background, typically when the user switches to a different
- * application. This event would emit when a Cordova app is put into
- * the background, however, it would not fire on a standard web browser.
- */
- pause = new Subject();
-
- /**
- * The resume event emits when the native platform pulls the application
- * out from the background. This event would emit when a Cordova app comes
- * out from the background, however, it would not fire on a standard web browser.
- */
- resume = new Subject();
-
- /**
- * The resize event emits when the browser window has changed dimensions. This
- * could be from a browser window being physically resized, or from a device
- * changing orientation.
- */
- resize = new Subject();
-
- constructor(@Inject(DOCUMENT) private doc: any, zone: NgZone) {
- zone.run(() => {
- this.win = doc.defaultView;
- this.backButton.subscribeWithPriority = function(priority, callback) {
- return this.subscribe(ev => {
- return ev.register(priority, processNextHandler => zone.run(() => callback(processNextHandler)));
- });
- };
-
- proxyEvent(this.pause, doc, 'pause');
- proxyEvent(this.resume, doc, 'resume');
- proxyEvent(this.backButton, doc, 'ionBackButton');
- proxyEvent(this.resize, this.win, 'resize');
-
- let readyResolve: (value: string) => void;
- this._readyPromise = new Promise(res => { readyResolve = res; });
- if (this.win && this.win['cordova']) {
- doc.addEventListener('deviceready', () => {
- readyResolve('cordova');
- }, { once: true });
- } else {
- readyResolve!('dom');
- }
- });
- }
-
- /**
- * @returns returns true/false based on platform.
- * @description
- * Depending on the platform the user is on, `is(platformName)` will
- * return `true` or `false`. Note that the same app can return `true`
- * for more than one platform name. For example, an app running from
- * an iPad would return `true` for the platform names: `mobile`,
- * `ios`, `ipad`, and `tablet`. Additionally, if the app was running
- * from Cordova then `cordova` would be true, and if it was running
- * from a web browser on the iPad then `mobileweb` would be `true`.
- *
- * ```
- * import { Platform } from 'ionic-angular';
- *
- * @Component({...})
- * export MyPage {
- * constructor(public platform: Platform) {
- * if (this.platform.is('ios')) {
- * // This will only print when on iOS
- * console.log('I am an iOS device!');
- * }
- * }
- * }
- * ```
- *
- * | Platform Name | Description |
- * |-----------------|------------------------------------|
- * | android | on a device running Android. |
- * | cordova | on a device running Cordova. |
- * | ios | on a device running iOS. |
- * | ipad | on an iPad device. |
- * | iphone | on an iPhone device. |
- * | phablet | on a phablet device. |
- * | tablet | on a tablet device. |
- * | electron | in Electron on a desktop device. |
- * | pwa | as a PWA app. |
- * | mobile | on a mobile device. |
- * | mobileweb | on a mobile device in a browser. |
- * | desktop | on a desktop device. |
- * | hybrid | is a cordova or capacitor app. |
- *
- */
- is(platformName: Platforms): boolean {
- return isPlatform(this.win, platformName);
- }
-
- /**
- * @returns the array of platforms
- * @description
- * Depending on what device you are on, `platforms` can return multiple values.
- * Each possible value is a hierarchy of platforms. For example, on an iPhone,
- * it would return `mobile`, `ios`, and `iphone`.
- *
- * ```
- * import { Platform } from 'ionic-angular';
- *
- * @Component({...})
- * export MyPage {
- * constructor(public platform: Platform) {
- * // This will print an array of the current platforms
- * console.log(this.platform.platforms());
- * }
- * }
- * ```
- */
- platforms(): string[] {
- return getPlatforms(this.win);
- }
-
- /**
- * Returns a promise when the platform is ready and native functionality
- * can be called. If the app is running from within a web browser, then
- * the promise will resolve when the DOM is ready. When the app is running
- * from an application engine such as Cordova, then the promise will
- * resolve when Cordova triggers the `deviceready` event.
- *
- * The resolved value is the `readySource`, which states which platform
- * ready was used. For example, when Cordova is ready, the resolved ready
- * source is `cordova`. The default ready source value will be `dom`. The
- * `readySource` is useful if different logic should run depending on the
- * platform the app is running from. For example, only Cordova can execute
- * the status bar plugin, so the web should not run status bar plugin logic.
- *
- * ```
- * import { Component } from '@angular/core';
- * import { Platform } from 'ionic-angular';
- *
- * @Component({...})
- * export MyApp {
- * constructor(public platform: Platform) {
- * this.platform.ready().then((readySource) => {
- * console.log('Platform ready from', readySource);
- * // Platform now ready, execute any required native code
- * });
- * }
- * }
- * ```
- */
- ready(): Promise {
- return this._readyPromise;
- }
-
- /**
- * Returns if this app is using right-to-left language direction or not.
- * We recommend the app's `index.html` file already has the correct `dir`
- * attribute value set, such as `` or ``.
- * [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir)
- */
- get isRTL(): boolean {
- return this.doc.dir === 'rtl';
- }
-
- /**
- * Get the query string parameter
- */
- getQueryParam(key: string): string | null {
- return readQueryParam(this.win.location.href, key);
- }
-
- /**
- * Returns `true` if the app is in landscape mode.
- */
- isLandscape(): boolean {
- return !this.isPortrait();
- }
-
- /**
- * Returns `true` if the app is in portait mode.
- */
- isPortrait(): boolean {
- return this.win.matchMedia && this.win.matchMedia('(orientation: portrait)').matches;
- }
-
- testUserAgent(expression: string): boolean {
- const nav = this.win.navigator;
- return !!(nav && nav.userAgent && nav.userAgent.indexOf(expression) >= 0);
- }
-
- /**
- * Get the current url.
- */
- url() {
- return this.win.location.href;
- }
-
- /**
- * Gets the width of the platform's viewport using `window.innerWidth`.
- */
- width() {
- return this.win.innerWidth;
- }
-
- /**
- * Gets the height of the platform's viewport using `window.innerHeight`.
- */
- height(): number {
- return this.win.innerHeight;
- }
-}
-
-const readQueryParam = (url: string, key: string) => {
- key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
- const regex = new RegExp('[\\?&]' + key + '=([^]*)');
- const results = regex.exec(url);
- return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
-};
-
-const proxyEvent = (emitter: Subject, el: EventTarget, eventName: string) => {
- if ((el as any)) {
- el.addEventListener(eventName, (ev: Event | undefined | null) => {
- // ?? cordova might emit "null" events
- emitter.next(ev != null ? (ev as any).detail as T : undefined);
- });
- }
-};
diff --git a/angular/src/providers/popover-controller.ts b/angular/src/providers/popover-controller.ts
deleted file mode 100644
index f86fd2b1c0b..00000000000
--- a/angular/src/providers/popover-controller.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
-import { PopoverOptions, popoverController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-import { AngularDelegate } from './angular-delegate';
-
-@Injectable()
-export class PopoverController extends OverlayBaseController {
-
- constructor(
- private angularDelegate: AngularDelegate,
- private resolver: ComponentFactoryResolver,
- private injector: Injector,
- ) {
- super(popoverController);
- }
-
- create(opts: PopoverOptions): Promise {
- return super.create({
- ...opts,
- delegate: this.angularDelegate.create(this.resolver, this.injector)
- });
- }
-}
diff --git a/angular/src/providers/toast-controller.ts b/angular/src/providers/toast-controller.ts
deleted file mode 100644
index d967b77b9f5..00000000000
--- a/angular/src/providers/toast-controller.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core';
-import { ToastOptions, toastController } from '@ionic/core';
-
-import { OverlayBaseController } from '../util/overlay';
-
-@Injectable({
- providedIn: 'root',
-})
-export class ToastController extends OverlayBaseController {
- constructor() {
- super(toastController);
- }
-}
diff --git a/angular/src/schematics/add/files/root/theme/variables.css b/angular/src/schematics/add/files/root/theme/variables.css
deleted file mode 100644
index dce6063246c..00000000000
--- a/angular/src/schematics/add/files/root/theme/variables.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* Ionic Variables and Theming. */
-/* This is just a placeholder file For more info, please see: */
-/* https://ionicframework.com/docs/theming/basics */
-
-/* To quickly generate your own theme, check out the color generator */
-/* https://ionicframework.com/docs/theming/color-generator */
diff --git a/angular/src/schematics/add/index.ts b/angular/src/schematics/add/index.ts
deleted file mode 100644
index a2465e29e74..00000000000
--- a/angular/src/schematics/add/index.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import { join, Path } from '@angular-devkit/core';
-import { apply, chain, mergeWith, move, Rule, SchematicContext, SchematicsException, template, Tree, url } from '@angular-devkit/schematics';
-import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
-import { addModuleImportToRootModule } from './../utils/ast';
-import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName, getWorkspace, WorkspaceProject, WorkspaceSchema } from './../utils/config';
-import { addPackageToPackageJson } from './../utils/package';
-import { Schema as IonAddOptions } from './schema';
-
-function addIonicAngularToPackageJson(): Rule {
- return (host: Tree) => {
- addPackageToPackageJson(host, 'dependencies', '@ionic/angular', 'latest');
- return host;
- };
-}
-
-function addIonicAngularToolkitToPackageJson(): Rule {
- return (host: Tree) => {
- addPackageToPackageJson(
- host,
- 'devDependencies',
- '@ionic/angular-toolkit',
- 'latest'
- );
- return host;
- };
-}
-
-function addIonicAngularModuleToAppModule(projectSourceRoot: Path): Rule {
- return (host: Tree) => {
- addModuleImportToRootModule(
- host,
- projectSourceRoot,
- 'IonicModule.forRoot()',
- '@ionic/angular'
- );
- return host;
- };
-}
-
-function addIonicStyles(projectName: string, projectSourceRoot: Path): Rule {
- return (host: Tree) => {
- const ionicStyles = [
- 'node_modules/@ionic/angular/css/normalize.css',
- 'node_modules/@ionic/angular/css/structure.css',
- 'node_modules/@ionic/angular/css/typography.css',
- 'node_modules/@ionic/angular/css/core.css',
- 'node_modules/@ionic/angular/css/padding.css',
- 'node_modules/@ionic/angular/css/float-elements.css',
- 'node_modules/@ionic/angular/css/text-alignment.css',
- 'node_modules/@ionic/angular/css/text-transformation.css',
- 'node_modules/@ionic/angular/css/flex-utils.css',
- `${projectSourceRoot}/theme/variables.css`
- ].forEach(entry => {
- addStyle(host, projectName, entry);
- });
- return host;
- };
-}
-
-function addIonicons(projectName: string): Rule {
- return (host: Tree) => {
- const ioniconsGlob = {
- glob: '**/*.svg',
- input: 'node_modules/ionicons/dist/ionicons/svg',
- output: './svg'
- };
- addAsset(host, projectName, ioniconsGlob);
- return host;
- };
-}
-
-function addIonicBuilder(projectName: string): Rule {
- return (host: Tree) => {
- addArchitectBuilder(host, projectName, 'ionic-cordova-serve', {
- builder: '@ionic/angular-toolkit:cordova-serve',
- options: {
- cordovaBuildTarget: `${projectName}:ionic-cordova-build`,
- devServerTarget: `${projectName}:serve`
- },
- configurations: {
- production: {
- cordovaBuildTarget: `${projectName}:ionic-cordova-build:production`,
- devServerTarget: `${projectName}:serve:production`
- }
- }
- });
- addArchitectBuilder(host, projectName, 'ionic-cordova-build', {
- builder: '@ionic/angular-toolkit:cordova-build',
- options: {
- browserTarget: `${projectName}:build`
- },
- configurations: {
- production: {
- browserTarget: `${projectName}:build:production`
- }
- }
- });
- return host;
- };
-}
-
-function installNodeDeps() {
- return (_host: Tree, context: SchematicContext) => {
- context.addTask(new NodePackageInstallTask());
- };
-}
-
-export default function ngAdd(options: IonAddOptions): Rule {
- return (host: Tree) => {
- const workspace: WorkspaceSchema = getWorkspace(host);
- if (!options.project) {
- options.project = getDefaultAngularAppName(workspace);
- }
- const project: WorkspaceProject = workspace.projects[options.project];
- if (project.projectType !== 'application') {
- throw new SchematicsException(
- `Ionic Add requires a project type of "application".`
- );
- }
- const sourcePath: Path = join(project.sourceRoot as Path);
- const rootTemplateSource = apply(url('./files/root'), [
- template({ ...options }),
- move(sourcePath)
- ]);
- return chain([
- // @ionic/angular
- addIonicAngularToPackageJson(),
- addIonicAngularToolkitToPackageJson(),
- addIonicAngularModuleToAppModule(sourcePath),
- addIonicBuilder(options.project),
- addIonicStyles(options.project, sourcePath),
- addIonicons(options.project),
- mergeWith(rootTemplateSource),
- // install freshly added dependencies
- installNodeDeps()
- ]);
- };
-}
diff --git a/angular/src/schematics/utils/ast.ts b/angular/src/schematics/utils/ast.ts
deleted file mode 100644
index 8bfd4c89030..00000000000
--- a/angular/src/schematics/utils/ast.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { SchematicsException, Tree } from '@angular-devkit/schematics';
-import { normalize } from '@angular-devkit/core';
-import * as ts from 'typescript';
-import { addImportToModule } from './devkit-utils/ast-utils';
-import { InsertChange } from './devkit-utils/change';
-
-/**
- * Reads file given path and returns TypeScript source file.
- */
-export function getSourceFile(host: Tree, path: string): ts.SourceFile {
- const buffer = host.read(path);
- if (!buffer) {
- throw new SchematicsException(`Could not find file for path: ${path}`);
- }
- const content = buffer.toString();
- const source = ts.createSourceFile(
- path,
- content,
- ts.ScriptTarget.Latest,
- true
- );
- return source;
-}
-
-/**
- * Import and add module to root app module.
- */
-export function addModuleImportToRootModule(
- host: Tree,
- projectSourceRoot: string,
- moduleName: string,
- importSrc: string
-) {
- addModuleImportToModule(
- host,
- normalize(`${projectSourceRoot}/app/app.module.ts`),
- moduleName,
- importSrc
- );
-}
-
-/**
- * Import and add module to specific module path.
- * @param host the tree we are updating
- * @param modulePath src location of the module to import
- * @param moduleName name of module to import
- * @param src src location to import
- */
-export function addModuleImportToModule(
- host: Tree,
- modulePath: string,
- moduleName: string,
- src: string
-) {
- const moduleSource = getSourceFile(host, modulePath);
- const changes = addImportToModule(moduleSource, modulePath, moduleName, src);
- const recorder = host.beginUpdate(modulePath);
-
- changes.forEach(change => {
- if (change instanceof InsertChange) {
- recorder.insertLeft(change.pos, change.toAdd);
- }
- });
-
- host.commitUpdate(recorder);
-}
diff --git a/angular/src/schematics/utils/config.ts b/angular/src/schematics/utils/config.ts
deleted file mode 100644
index 39f0576431e..00000000000
--- a/angular/src/schematics/utils/config.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { SchematicsException, Tree } from '@angular-devkit/schematics';
-import { experimental, parseJson, JsonParseMode } from '@angular-devkit/core';
-
-const CONFIG_PATH = 'angular.json';
-
-export function readConfig(host: Tree) {
- const sourceText = host.read(CONFIG_PATH)!.toString('utf-8');
- return JSON.parse(sourceText);
-}
-
-export function writeConfig(host: Tree, config: JSON) {
- host.overwrite(CONFIG_PATH, JSON.stringify(config, null, 2));
-}
-
-function isAngularBrowserProject(projectConfig: any) {
- if (projectConfig.projectType === 'application') {
- const buildConfig = projectConfig.architect.build;
- return buildConfig.builder === '@angular-devkit/build-angular:browser';
- }
-
- return false;
-}
-
-export function getDefaultAngularAppName(config: any): string {
- const projects = config.projects;
- const projectNames = Object.keys(projects);
-
- for (const projectName of projectNames) {
- const projectConfig = projects[projectName];
- if (isAngularBrowserProject(projectConfig)) {
- return projectName;
- }
- }
-
- return projectNames[0];
-}
-
-export function getAngularAppConfig(config: any, projectName: string): any | never {
- if (!config.projects.hasOwnProperty(projectName)) {
- throw new SchematicsException(`Could not find project: ${projectName}`);
- }
-
- const projectConfig = config.projects[projectName];
- if (isAngularBrowserProject(projectConfig)) {
- return projectConfig;
- }
-
- if (config.projectType !== 'application') {
- throw new SchematicsException(`Invalid projectType for ${projectName}: ${config.projectType}`);
- } else {
- const buildConfig = projectConfig.architect.build;
- throw new SchematicsException(`Invalid builder for ${projectName}: ${buildConfig.builder}`);
- }
-}
-
-export function addStyle(host: Tree, projectName: string, stylePath: string) {
- const config = readConfig(host);
- const appConfig = getAngularAppConfig(config, projectName);
- appConfig.architect.build.options.styles.push({
- input: stylePath
- });
- writeConfig(host, config);
-}
-
-export function addAsset(host: Tree, projectName: string, asset: string | {glob: string; input: string; output: string}) {
- const config = readConfig(host);
- const appConfig = getAngularAppConfig(config, projectName);
- appConfig.architect.build.options.assets.push(asset);
- writeConfig(host, config);
-}
-
-export function addArchitectBuilder(host: Tree, projectName: string, builderName: string, builderOpts: any): void | never {
- const config = readConfig(host);
- const appConfig = getAngularAppConfig(config, projectName);
- appConfig.architect[builderName] = builderOpts;
- writeConfig(host, config);
-}
-
-export type WorkspaceSchema = experimental.workspace.WorkspaceSchema;
-export type WorkspaceProject = experimental.workspace.WorkspaceProject;
-
-export function getWorkspacePath(host: Tree): string {
- const possibleFiles = ['/angular.json', '/.angular.json'];
- const path = possibleFiles.filter(path => host.exists(path))[0];
-
- return path;
-}
-
-export function getWorkspace(host: Tree): WorkspaceSchema {
- const path = getWorkspacePath(host);
- const configBuffer = host.read(path);
- if (configBuffer === null) {
- throw new SchematicsException(`Could not find (${path})`);
- }
- const content = configBuffer.toString();
-
- return (parseJson(content, JsonParseMode.Loose) as {}) as WorkspaceSchema;
-}
diff --git a/angular/src/schematics/utils/devkit-utils/ast-utils.ts b/angular/src/schematics/utils/devkit-utils/ast-utils.ts
deleted file mode 100644
index f18d7327ae7..00000000000
--- a/angular/src/schematics/utils/devkit-utils/ast-utils.ts
+++ /dev/null
@@ -1,571 +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 * as ts from 'typescript';
-import { Change, InsertChange, NoopChange } from './change';
-
-
-/**
- * Add Import `import { symbolName } from fileName` if the import doesn't exit
- * already. Assumes fileToEdit can be resolved and accessed.
- * @param fileToEdit (file we want to add import to)
- * @param symbolName (item to import)
- * @param fileName (path to the file)
- * @param isDefault (if true, import follows style for importing default exports)
- * @return Change
- */
-export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolName: string,
- fileName: string, isDefault = false): Change {
- const rootNode = source;
- const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
-
- // get nodes that map to import statements from the file fileName
- const relevantImports = allImports.filter(node => {
- // StringLiteral of the ImportDeclaration is the import file (fileName in this case).
- const importFiles = node.getChildren()
- .filter(child => child.kind === ts.SyntaxKind.StringLiteral)
- .map(n => (n as ts.StringLiteral).text);
-
- return importFiles.filter(file => file === fileName).length === 1;
- });
-
- if (relevantImports.length > 0) {
- let importsAsterisk = false;
- // imports from import file
- const imports: ts.Node[] = [];
- relevantImports.forEach(n => {
- Array.prototype.push.apply(imports, findNodes(n, ts.SyntaxKind.Identifier));
- if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
- importsAsterisk = true;
- }
- });
-
- // if imports * from fileName, don't add symbolName
- if (importsAsterisk) {
- return new NoopChange();
- }
-
- const importTextNodes = imports.filter(n => (n as ts.Identifier).text === symbolName);
-
- // insert import if it's not there
- if (importTextNodes.length === 0) {
- const fallbackPos =
- findNodes(relevantImports[0], ts.SyntaxKind.CloseBraceToken)[0].getStart() ||
- findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart();
-
- return insertAfterLastOccurrence(imports, `, ${symbolName}`, fileToEdit, fallbackPos);
- }
-
- return new NoopChange();
- }
-
- // no such import declaration exists
- const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral)
- .filter((n: ts.StringLiteral) => n.text === 'use strict');
- let fallbackPos = 0;
- if (useStrict.length > 0) {
- fallbackPos = useStrict[0].end;
- }
- const open = isDefault ? '' : '{ ';
- const close = isDefault ? '' : ' }';
- // if there are no imports or 'use strict' statement, insert import at beginning of file
- const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
- const separator = insertAtBeginning ? '' : ';\n';
- const toInsert = `${separator}import ${open}${symbolName}${close}` +
- ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
-
- return insertAfterLastOccurrence(
- allImports,
- toInsert,
- fileToEdit,
- fallbackPos,
- ts.SyntaxKind.StringLiteral,
- );
-}
-
-
-/**
- * Find all nodes from the AST in the subtree of node of SyntaxKind kind.
- * @param node
- * @param kind
- * @param max The maximum number of items to return.
- * @return all nodes of kind, or [] if none is found
- */
-export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity): ts.Node[] {
- if (!node || max == 0) {
- return [];
- }
-
- const arr: ts.Node[] = [];
- if (node.kind === kind) {
- arr.push(node);
- max--;
- }
- if (max > 0) {
- for (const child of node.getChildren()) {
- findNodes(child, kind, max).forEach(node => {
- if (max > 0) {
- arr.push(node);
- }
- max--;
- });
-
- if (max <= 0) {
- break;
- }
- }
- }
-
- return arr;
-}
-
-
-/**
- * Get all the nodes from a source.
- * @param sourceFile The source file object.
- * @returns {Observable} An observable of all the nodes in the source.
- */
-export function getSourceNodes(sourceFile: ts.SourceFile): ts.Node[] {
- const nodes: ts.Node[] = [sourceFile];
- const result = [];
-
- while (nodes.length > 0) {
- const node = nodes.shift();
-
- if (node) {
- result.push(node);
- if (node.getChildCount(sourceFile) >= 0) {
- nodes.unshift(...node.getChildren());
- }
- }
- }
-
- return result;
-}
-
-export function findNode(node: ts.Node, kind: ts.SyntaxKind, text: string): ts.Node | null {
- if (node.kind === kind && node.getText() === text) {
- // throw new Error(node.getText());
- return node;
- }
-
- let foundNode: ts.Node | null = null;
- ts.forEachChild(node, childNode => {
- foundNode = foundNode || findNode(childNode, kind, text);
- });
-
- return foundNode;
-}
-
-
-/**
- * Helper for sorting nodes.
- * @return function to sort nodes in increasing order of position in sourceFile
- */
-function nodesByPosition(first: ts.Node, second: ts.Node): number {
- return first.getStart() - second.getStart();
-}
-
-
-/**
- * Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]`
- * or after the last of occurence of `syntaxKind` if the last occurence is a sub child
- * of ts.SyntaxKind[nodes[i].kind] and save the changes in file.
- *
- * @param nodes insert after the last occurence of nodes
- * @param toInsert string to insert
- * @param file file to insert changes into
- * @param fallbackPos position to insert if toInsert happens to be the first occurence
- * @param syntaxKind the ts.SyntaxKind of the subchildren to insert after
- * @return Change instance
- * @throw Error if toInsert is first occurence but fall back is not set
- */
-export function insertAfterLastOccurrence(nodes: ts.Node[],
- toInsert: string,
- file: string,
- fallbackPos: number,
- syntaxKind?: ts.SyntaxKind): Change {
- // sort() has a side effect, so make a copy so that we won't overwrite the parent's object.
- let lastItem = [...nodes].sort(nodesByPosition).pop();
- if (!lastItem) {
- throw new Error();
- }
- if (syntaxKind) {
- lastItem = findNodes(lastItem, syntaxKind).sort(nodesByPosition).pop();
- }
- if (!lastItem && fallbackPos == undefined) {
- throw new Error(`tried to insert ${toInsert} as first occurence with no fallback position`);
- }
- const lastItemPosition: number = lastItem ? lastItem.getEnd() : fallbackPos;
-
- return new InsertChange(file, lastItemPosition, toInsert);
-}
-
-
-export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null {
- if (node.kind == ts.SyntaxKind.Identifier) {
- return (node as ts.Identifier).text;
- } else if (node.kind == ts.SyntaxKind.StringLiteral) {
- return (node as ts.StringLiteral).text;
- } else {
- return null;
- }
-}
-
-
-function _angularImportsFromNode(node: ts.ImportDeclaration,
- _sourceFile: ts.SourceFile): {[name: string]: string} {
- const ms = node.moduleSpecifier;
- let modulePath: string;
- switch (ms.kind) {
- case ts.SyntaxKind.StringLiteral:
- modulePath = (ms as ts.StringLiteral).text;
- break;
- default:
- return {};
- }
-
- if (!modulePath.startsWith('@angular/')) {
- return {};
- }
-
- if (node.importClause) {
- if (node.importClause.name) {
- // This is of the form `import Name from 'path'`. Ignore.
- return {};
- } else if (node.importClause.namedBindings) {
- const nb = node.importClause.namedBindings;
- if (nb.kind == ts.SyntaxKind.NamespaceImport) {
- // This is of the form `import * as name from 'path'`. Return `name.`.
- return {
- [(nb as ts.NamespaceImport).name.text + '.']: modulePath,
- };
- } else {
- // This is of the form `import {a,b,c} from 'path'`
- const namedImports = nb as ts.NamedImports;
-
- return namedImports.elements
- .map((is: ts.ImportSpecifier) => is.propertyName ? is.propertyName.text : is.name.text)
- .reduce((acc: {[name: string]: string}, curr: string) => {
- acc[curr] = modulePath;
-
- return acc;
- }, {});
- }
- }
-
- return {};
- } else {
- // This is of the form `import 'path';`. Nothing to do.
- return {};
- }
-}
-
-
-export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
- module: string): ts.Node[] {
- const angularImports: {[name: string]: string}
- = findNodes(source, ts.SyntaxKind.ImportDeclaration)
- .map((node: ts.ImportDeclaration) => _angularImportsFromNode(node, source))
- .reduce((acc: {[name: string]: string}, current: {[name: string]: string}) => {
- for (const key of Object.keys(current)) {
- acc[key] = current[key];
- }
-
- return acc;
- }, {});
-
- return getSourceNodes(source)
- .filter(node => {
- return node.kind == ts.SyntaxKind.Decorator
- && (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression;
- })
- .map(node => (node as ts.Decorator).expression as ts.CallExpression)
- .filter(expr => {
- if (expr.expression.kind == ts.SyntaxKind.Identifier) {
- const id = expr.expression as ts.Identifier;
-
- return id.getFullText(source) == identifier
- && angularImports[id.getFullText(source)] === module;
- } else if (expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
- // This covers foo.NgModule when importing * as foo.
- const paExpr = expr.expression as ts.PropertyAccessExpression;
- // If the left expression is not an identifier, just give up at that point.
- if (paExpr.expression.kind !== ts.SyntaxKind.Identifier) {
- return false;
- }
-
- const id = paExpr.name.text;
- const moduleId = (paExpr.expression as ts.Identifier).getText(source);
-
- return id === identifier && (angularImports[moduleId + '.'] === module);
- }
-
- return false;
- })
- .filter(expr => expr.arguments[0]
- && expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
- .map(expr => expr.arguments[0] as ts.ObjectLiteralExpression);
-}
-
-function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration|undefined {
- if (ts.isClassDeclaration(node)) {
- return node;
- }
-
- return node.parent && findClassDeclarationParent(node.parent);
-}
-
-/**
- * Given a source file with @NgModule class(es), find the name of the first @NgModule class.
- *
- * @param source source file containing one or more @NgModule
- * @returns the name of the first @NgModule, or `undefined` if none is found
- */
-export function getFirstNgModuleName(source: ts.SourceFile): string|undefined {
- // First, find the @NgModule decorators.
- const ngModulesMetadata = getDecoratorMetadata(source, 'NgModule', '@angular/core');
- if (ngModulesMetadata.length === 0) {
- return undefined;
- }
-
- // Then walk parent pointers up the AST, looking for the ClassDeclaration parent of the NgModule
- // metadata.
- const moduleClass = findClassDeclarationParent(ngModulesMetadata[0]);
- if (!moduleClass || !moduleClass.name) {
- return undefined;
- }
-
- // Get the class name of the module ClassDeclaration.
- return moduleClass.name.text;
-}
-
-export function addSymbolToNgModuleMetadata(
- source: ts.SourceFile,
- ngModulePath: string,
- metadataField: string,
- symbolName: string,
- importPath: string | null = null,
-): Change[] {
- const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
- let node: any = nodes[0]; // tslint:disable-line:no-any
-
- // Find the decorator declaration.
- if (!node) {
- return [];
- }
-
- // Get all the children property assignment of object literals.
- const matchingProperties: ts.ObjectLiteralElement[] =
- (node as ts.ObjectLiteralExpression).properties
- .filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
- // Filter out every fields that's not "metadataField". Also handles string literals
- // (but not expressions).
- .filter((prop: ts.PropertyAssignment) => {
- const name = prop.name;
- switch (name.kind) {
- case ts.SyntaxKind.Identifier:
- return (name as ts.Identifier).getText(source) == metadataField;
- case ts.SyntaxKind.StringLiteral:
- return (name as ts.StringLiteral).text == metadataField;
- }
-
- return false;
- });
-
- // Get the last node of the array literal.
- if (!matchingProperties) {
- return [];
- }
- if (matchingProperties.length == 0) {
- // We haven't found the field in the metadata declaration. Insert a new field.
- const expr = node as ts.ObjectLiteralExpression;
- let position: number;
- let toInsert: string;
- if (expr.properties.length == 0) {
- position = expr.getEnd() - 1;
- toInsert = ` ${metadataField}: [${symbolName}]\n`;
- } else {
- node = expr.properties[expr.properties.length - 1];
- position = node.getEnd();
- // Get the indentation of the last element, if any.
- const text = node.getFullText(source);
- const matches = text.match(/^\r?\n\s*/);
- if (matches.length > 0) {
- toInsert = `,${matches[0]}${metadataField}: [${symbolName}]`;
- } else {
- toInsert = `, ${metadataField}: [${symbolName}]`;
- }
- }
- if (importPath !== null) {
- return [
- new InsertChange(ngModulePath, position, toInsert),
- insertImport(source, ngModulePath, symbolName.replace(/\..*$/, ''), importPath),
- ];
- } else {
- return [new InsertChange(ngModulePath, position, toInsert)];
- }
- }
- const assignment = matchingProperties[0] as ts.PropertyAssignment;
-
- // If it's not an array, nothing we can do really.
- if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
- return [];
- }
-
- const arrLiteral = assignment.initializer as ts.ArrayLiteralExpression;
- if (arrLiteral.elements.length == 0) {
- // Forward the property.
- node = arrLiteral;
- } else {
- node = arrLiteral.elements;
- }
-
- if (!node) {
- console.log('No app module found. Please add your new class to your component.');
-
- return [];
- }
-
- if (Array.isArray(node)) {
- const nodeArray = node as {} as Array;
- const symbolsArray = nodeArray.map(node => node.getText());
- if (symbolsArray.includes(symbolName)) {
- return [];
- }
-
- node = node[node.length - 1];
- }
-
- let toInsert: string;
- let position = node.getEnd();
- if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
- // We haven't found the field in the metadata declaration. Insert a new
- // field.
- const expr = node as ts.ObjectLiteralExpression;
- if (expr.properties.length == 0) {
- position = expr.getEnd() - 1;
- toInsert = ` ${metadataField}: [${symbolName}]\n`;
- } else {
- node = expr.properties[expr.properties.length - 1];
- position = node.getEnd();
- // Get the indentation of the last element, if any.
- const text = node.getFullText(source);
- if (text.match('^\r?\r?\n')) {
- toInsert = `,${text.match(/^\r?\n\s+/)[0]}${metadataField}: [${symbolName}]`;
- } else {
- toInsert = `, ${metadataField}: [${symbolName}]`;
- }
- }
- } else if (node.kind == ts.SyntaxKind.ArrayLiteralExpression) {
- // We found the field but it's empty. Insert it just before the `]`.
- position--;
- toInsert = `${symbolName}`;
- } else {
- // Get the indentation of the last element, if any.
- const text = node.getFullText(source);
- if (text.match(/^\r?\n/)) {
- toInsert = `,${text.match(/^\r?\n(\r?)\s+/)[0]}${symbolName}`;
- } else {
- toInsert = `, ${symbolName}`;
- }
- }
- if (importPath !== null) {
- return [
- new InsertChange(ngModulePath, position, toInsert),
- insertImport(source, ngModulePath, symbolName.replace(/\..*$/, ''), importPath),
- ];
- }
-
- return [new InsertChange(ngModulePath, position, toInsert)];
-}
-
-/**
- * Custom function to insert a declaration (component, pipe, directive)
- * into NgModule declarations. It also imports the component.
- */
-export function addDeclarationToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
- return addSymbolToNgModuleMetadata(
- source, modulePath, 'declarations', classifiedName, importPath);
-}
-
-/**
- * Custom function to insert an NgModule into NgModule imports. It also imports the module.
- */
-export function addImportToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
-
- return addSymbolToNgModuleMetadata(source, modulePath, 'imports', classifiedName, importPath);
-}
-
-/**
- * Custom function to insert a provider into NgModule. It also imports it.
- */
-export function addProviderToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
- return addSymbolToNgModuleMetadata(source, modulePath, 'providers', classifiedName, importPath);
-}
-
-/**
- * Custom function to insert an export into NgModule. It also imports it.
- */
-export function addExportToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
- return addSymbolToNgModuleMetadata(source, modulePath, 'exports', classifiedName, importPath);
-}
-
-/**
- * Custom function to insert an export into NgModule. It also imports it.
- */
-export function addBootstrapToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
- return addSymbolToNgModuleMetadata(source, modulePath, 'bootstrap', classifiedName, importPath);
-}
-
-/**
- * Custom function to insert an entryComponent into NgModule. It also imports it.
- */
-export function addEntryComponentToModule(source: ts.SourceFile,
- modulePath: string, classifiedName: string,
- importPath: string): Change[] {
- return addSymbolToNgModuleMetadata(
- source, modulePath,
- 'entryComponents', classifiedName, importPath,
- );
-}
-
-/**
- * Determine if an import already exists.
- */
-export function isImported(source: ts.SourceFile,
- classifiedName: string,
- importPath: string): boolean {
- const allNodes = getSourceNodes(source);
- const matchingNodes = allNodes
- .filter(node => node.kind === ts.SyntaxKind.ImportDeclaration)
- .filter((imp: ts.ImportDeclaration) => imp.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral)
- .filter((imp: ts.ImportDeclaration) => {
- return ( imp.moduleSpecifier).text === importPath;
- })
- .filter((imp: ts.ImportDeclaration) => {
- if (!imp.importClause) {
- return false;
- }
- const nodes = findNodes(imp.importClause, ts.SyntaxKind.ImportSpecifier)
- .filter(n => n.getText() === classifiedName);
-
- return nodes.length > 0;
- });
-
- return matchingNodes.length > 0;
-}
diff --git a/angular/src/schematics/utils/devkit-utils/change.ts b/angular/src/schematics/utils/devkit-utils/change.ts
deleted file mode 100644
index 12556352abd..00000000000
--- a/angular/src/schematics/utils/devkit-utils/change.ts
+++ /dev/null
@@ -1,127 +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
- */
-export interface Host {
- write(path: string, content: string): Promise;
- read(path: string): Promise;
-}
-
-
-export interface Change {
- apply(host: Host): Promise;
-
- // The file this change should be applied to. Some changes might not apply to
- // a file (maybe the config).
- readonly path: string | null;
-
- // The order this change should be applied. Normally the position inside the file.
- // Changes are applied from the bottom of a file to the top.
- readonly order: number;
-
- // The description of this change. This will be outputted in a dry or verbose run.
- readonly description: string;
-}
-
-
-/**
- * An operation that does nothing.
- */
-export class NoopChange implements Change {
- description = 'No operation.';
- order = Infinity;
- path = null;
- apply() { return Promise.resolve(); }
-}
-
-
-/**
- * Will add text to the source code.
- */
-export class InsertChange implements Change {
-
- order: number;
- description: string;
-
- constructor(public path: string, public pos: number, public toAdd: string) {
- if (pos < 0) {
- throw new Error('Negative positions are invalid');
- }
- this.description = `Inserted ${toAdd} into position ${pos} of ${path}`;
- this.order = pos;
- }
-
- /**
- * This method does not insert spaces if there is none in the original string.
- */
- apply(host: Host) {
- return host.read(this.path).then(content => {
- const prefix = content.substring(0, this.pos);
- const suffix = content.substring(this.pos);
-
- return host.write(this.path, `${prefix}${this.toAdd}${suffix}`);
- });
- }
-}
-
-/**
- * Will remove text from the source code.
- */
-export class RemoveChange implements Change {
-
- order: number;
- description: string;
-
- constructor(public path: string, private pos: number, private toRemove: string) {
- if (pos < 0) {
- throw new Error('Negative positions are invalid');
- }
- this.description = `Removed ${toRemove} into position ${pos} of ${path}`;
- this.order = pos;
- }
-
- apply(host: Host): Promise {
- return host.read(this.path).then(content => {
- const prefix = content.substring(0, this.pos);
- const suffix = content.substring(this.pos + this.toRemove.length);
-
- // TODO: throw error if toRemove doesn't match removed string.
- return host.write(this.path, `${prefix}${suffix}`);
- });
- }
-}
-
-/**
- * Will replace text from the source code.
- */
-export class ReplaceChange implements Change {
- order: number;
- description: string;
-
- constructor(public path: string, private pos: number, private oldText: string,
- private newText: string) {
- if (pos < 0) {
- throw new Error('Negative positions are invalid');
- }
- this.description = `Replaced ${oldText} into position ${pos} of ${path} with ${newText}`;
- this.order = pos;
- }
-
- apply(host: Host): Promise {
- return host.read(this.path).then(content => {
- const prefix = content.substring(0, this.pos);
- const suffix = content.substring(this.pos + this.oldText.length);
- const text = content.substring(this.pos, this.pos + this.oldText.length);
-
- if (text !== this.oldText) {
- return Promise.reject(new Error(`Invalid replace: "${text}" != "${this.oldText}".`));
- }
-
- // TODO: throw error if oldText doesn't match removed string.
- return host.write(this.path, `${prefix}${this.newText}${suffix}`);
- });
- }
-}
diff --git a/angular/src/schematics/utils/devkit-utils/readme.md b/angular/src/schematics/utils/devkit-utils/readme.md
deleted file mode 100644
index 7c00152314a..00000000000
--- a/angular/src/schematics/utils/devkit-utils/readme.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### Devkit Utils
-
-These are utility files copied over from `@angular-devkit`.
-They are not exported so they need to be manually copied over.
-Please do not edit directly.
-
-
diff --git a/angular/src/schematics/utils/devkit-utils/route-utils.ts b/angular/src/schematics/utils/devkit-utils/route-utils.ts
deleted file mode 100644
index 066a0b11296..00000000000
--- a/angular/src/schematics/utils/devkit-utils/route-utils.ts
+++ /dev/null
@@ -1,110 +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 * as ts from 'typescript';
-import { findNodes, insertAfterLastOccurrence } from './ast-utils';
-import { Change, NoopChange } from './change';
-
-/**
- * Add Import `import { symbolName } from fileName` if the import doesn't exit
- * already. Assumes fileToEdit can be resolved and accessed.
- * @param fileToEdit (file we want to add import to)
- * @param symbolName (item to import)
- * @param fileName (path to the file)
- * @param isDefault (if true, import follows style for importing default exports)
- * @return Change
- */
-
-export function insertImport(
- source: ts.SourceFile,
- fileToEdit: string,
- symbolName: string,
- fileName: string,
- isDefault = false
-): Change {
- const rootNode = source;
- const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
-
- // get nodes that map to import statements from the file fileName
- const relevantImports = allImports.filter(node => {
- // StringLiteral of the ImportDeclaration is the import file (fileName in this case).
- const importFiles = node
- .getChildren()
- .filter(child => child.kind === ts.SyntaxKind.StringLiteral)
- .map(n => (n as ts.StringLiteral).text);
-
- return importFiles.filter(file => file === fileName).length === 1;
- });
-
- if (relevantImports.length > 0) {
- let importsAsterisk = false;
- // imports from import file
- const imports: ts.Node[] = [];
- relevantImports.forEach(n => {
- Array.prototype.push.apply(
- imports,
- findNodes(n, ts.SyntaxKind.Identifier)
- );
- if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
- importsAsterisk = true;
- }
- });
-
- // if imports * from fileName, don't add symbolName
- if (importsAsterisk) {
- return new NoopChange();
- }
-
- const importTextNodes = imports.filter(
- n => (n as ts.Identifier).text === symbolName
- );
-
- // insert import if it's not there
- if (importTextNodes.length === 0) {
- const fallbackPos =
- findNodes(
- relevantImports[0],
- ts.SyntaxKind.CloseBraceToken
- )[0].getStart() ||
- findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart();
-
- return insertAfterLastOccurrence(
- imports,
- `, ${symbolName}`,
- fileToEdit,
- fallbackPos
- );
- }
-
- return new NoopChange();
- }
-
- // no such import declaration exists
- const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter(
- (n: ts.StringLiteral) => n.text === 'use strict'
- );
- let fallbackPos = 0;
- if (useStrict.length > 0) {
- fallbackPos = useStrict[0].end;
- }
- const open = isDefault ? '' : '{ ';
- const close = isDefault ? '' : ' }';
- // if there are no imports or 'use strict' statement, insert import at beginning of file
- const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
- const separator = insertAtBeginning ? '' : ';\n';
- const toInsert =
- `${separator}import ${open}${symbolName}${close}` +
- ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
-
- return insertAfterLastOccurrence(
- allImports,
- toInsert,
- fileToEdit,
- fallbackPos,
- ts.SyntaxKind.StringLiteral
- );
-}
diff --git a/angular/src/schematics/utils/package.ts b/angular/src/schematics/utils/package.ts
deleted file mode 100644
index c07e8ba23ad..00000000000
--- a/angular/src/schematics/utils/package.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import {Tree} from '@angular-devkit/schematics';
-
-/**
- * Adds a package to the package.json
- */
-export function addPackageToPackageJson(host: Tree, type: string, pkg: string, version: string) {
- if (host.exists('package.json')) {
- const sourceText = host.read('package.json')!.toString('utf-8');
- const json = JSON.parse(sourceText);
- if (!json[type]) {
- json[type] = {};
- }
-
- if (!json[type][pkg]) {
- json[type][pkg] = version;
- }
-
- host.overwrite('package.json', JSON.stringify(json, null, 2));
- }
-
- return host;
-}
diff --git a/angular/src/types/interfaces.ts b/angular/src/types/interfaces.ts
deleted file mode 100644
index 7286cabcc91..00000000000
--- a/angular/src/types/interfaces.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-
-export interface IonicGlobal {
- config?: any;
- asyncQueue?: boolean;
-}
-
-export interface IonicWindow extends Window {
- Ionic: IonicGlobal;
- __zone_symbol__requestAnimationFrame?: (ts: FrameRequestCallback) => number;
-}
-
-export interface HTMLStencilElement extends HTMLElement {
- componentOnReady(): Promise;
- forceUpdate(): void;
-}
diff --git a/angular/src/util/ionic-router-reuse-strategy.ts b/angular/src/util/ionic-router-reuse-strategy.ts
deleted file mode 100644
index d1005d5005e..00000000000
--- a/angular/src/util/ionic-router-reuse-strategy.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
-
-export class IonicRouteStrategy implements RouteReuseStrategy {
-
- shouldDetach(_route: ActivatedRouteSnapshot): boolean {
- return false;
- }
-
- shouldAttach(_route: ActivatedRouteSnapshot): boolean {
- return false;
- }
-
- store(_route: ActivatedRouteSnapshot, _detachedTree: DetachedRouteHandle): void {
- return;
- }
-
- retrieve(_route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
- return null;
- }
-
- shouldReuseRoute(
- future: ActivatedRouteSnapshot,
- curr: ActivatedRouteSnapshot
- ): boolean {
- if (future.routeConfig !== curr.routeConfig) {
- return false;
- }
-
- // checking router params
- const futureParams = future.params;
- const currentParams = curr.params;
- const keysA = Object.keys(futureParams);
- const keysB = Object.keys(currentParams);
-
- if (keysA.length !== keysB.length) {
- return false;
- }
-
- // Test for A's keys different from B.
- for (const key of keysA) {
- if (currentParams[key] !== futureParams[key]) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/angular/src/util/overlay.ts b/angular/src/util/overlay.ts
deleted file mode 100644
index 4310d6f2437..00000000000
--- a/angular/src/util/overlay.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-
-interface ControllerShape {
- create(options: Opts): Promise;
- dismiss(data?: any, role?: string, id?: string): Promise;
- getTop(): Promise;
-}
-
-export class OverlayBaseController implements ControllerShape {
- constructor(private ctrl: ControllerShape) {}
-
- /**
- * Creates a new overlay
- */
- create(opts?: Opts) {
- // TODO: next major release opts is not optional
- return this.ctrl.create((opts || {}) as any);
- }
-
- /**
- * When `id` is not provided, it dismisses the top overlay.
- */
- dismiss(data?: any, role?: string, id?: string) {
- return this.ctrl.dismiss(data, role, id);
- }
-
- /**
- * Returns the top overlay.
- */
- getTop() {
- return this.ctrl.getTop();
- }
-}
diff --git a/angular/src/util/util.ts b/angular/src/util/util.ts
deleted file mode 100644
index 37bbe613f50..00000000000
--- a/angular/src/util/util.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-
-declare const __zone_symbol__requestAnimationFrame: any;
-declare const requestAnimationFrame: any;
-
-export const raf = (h: any) => {
- if (typeof __zone_symbol__requestAnimationFrame === 'function') {
- return __zone_symbol__requestAnimationFrame(h);
- }
- if (typeof requestAnimationFrame === 'function') {
- return requestAnimationFrame(h);
- }
- return setTimeout(h);
-};
diff --git a/angular/test/test-app/.gitignore b/angular/test/test-app/.gitignore
deleted file mode 100644
index 85158b7a442..00000000000
--- a/angular/test/test-app/.gitignore
+++ /dev/null
@@ -1,43 +0,0 @@
-# See http://help.github.com/ignore-files/ for more about ignoring files.
-
-# compiled output
-/dist
-/tmp
-/out-tsc
-
-# dependencies
-/node_modules
-
-# profiling files
-chrome-profiler-events.json
-speed-measure-plugin.json
-
-# IDEs and editors
-/.idea
-.project
-.classpath
-.c9/
-*.launch
-.settings/
-*.sublime-workspace
-
-# IDE - VSCode
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
-
-# misc
-/.sass-cache
-/connect.lock
-/coverage
-/libpeerconnection.log
-npm-debug.log
-yarn-error.log
-testem.log
-/typings
-
-# System Files
-.DS_Store
-Thumbs.db
diff --git a/angular/test/test-app/.npmrc b/angular/test/test-app/.npmrc
deleted file mode 100644
index 43c97e719a5..00000000000
--- a/angular/test/test-app/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-package-lock=false
diff --git a/angular/test/test-app/README.md b/angular/test/test-app/README.md
deleted file mode 100644
index 8d93d2cf3cc..00000000000
--- a/angular/test/test-app/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Ionic Angular Test App
-
-```
-npm install
-npm run sync:build
-npm start
-```
diff --git a/angular/test/test-app/angular.json b/angular/test/test-app/angular.json
deleted file mode 100644
index edf436e66c9..00000000000
--- a/angular/test/test-app/angular.json
+++ /dev/null
@@ -1,168 +0,0 @@
-{
- "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
- "version": 1,
- "newProjectRoot": "projects",
- "projects": {
- "test-app": {
- "root": "",
- "sourceRoot": "src",
- "projectType": "application",
- "prefix": "app",
- "schematics": {},
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "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",
- {
- "glob": "**/*",
- "input": "src/assets",
- "output": "assets"
- },
- {
- "glob": "**/*.svg",
- "input": "node_modules/ionicons/dist/ionicons/svg",
- "output": "./svg"
- }
- ],
- "styles": ["src/styles.css"],
- "scripts": []
- },
- "configurations": {
- "production": {
- "fileReplacements": [
- {
- "replace": "src/environments/environment.ts",
- "with": "src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "progress": false,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "budgets": [
- {
- "type": "initial",
- "maximumWarning": "2mb",
- "maximumError": "5mb"
- },
- {
- "type": "anyComponentStyle",
- "maximumWarning": "6kb"
- }
- ]
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "test-app:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "test-app:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "test-app:build"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "src/test.ts",
- "polyfills": "src/polyfills.ts",
- "tsConfig": "tsconfig.spec.json",
- "karmaConfig": "karma.conf.js",
- "styles": ["src/styles.css"],
- "scripts": [],
- "assets": ["src/favicon.ico", "src/assets"]
- }
- },
- "e2e": {
- "builder": "@angular-devkit/build-angular:protractor",
- "options": {
- "protractorConfig": "e2e/protractor.conf.js",
- "devServerTarget": "test-app:serve"
- },
- "configurations": {
- "production": {
- "devServerTarget": "test-app:serve:production"
- },
- "ci": {
- "devServerTarget": "test-app:serve:ci"
- }
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
- "exclude": ["**/node_modules/**"]
- }
- },
- "server": {
- "builder": "@angular-devkit/build-angular:server",
- "options": {
- "outputPath": "dist/test-app/server",
- "main": "server.ts",
- "tsConfig": "tsconfig.server.json"
- },
- "configurations": {
- "production": {
- "outputHashing": "media",
- "fileReplacements": [
- {
- "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": []
- }
- }
- }
- }
- },
- "defaultProject": "test-app"
-}
diff --git a/angular/test/test-app/browserslist b/angular/test/test-app/browserslist
deleted file mode 100644
index b15c7fae51a..00000000000
--- a/angular/test/test-app/browserslist
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
-# For additional information regarding the format and rule options, please see:
-# https://github.com/browserslist/browserslist#queries
-
-# You can see what browsers were selected by your queries by running:
-# npx browserslist
-
-> 0.5%
-last 2 versions
-Firefox ESR
-not dead
-not IE 9-11 # For IE 9-11 support, remove 'not'.
diff --git a/angular/test/test-app/e2e/protractor.conf.js b/angular/test/test-app/e2e/protractor.conf.js
deleted file mode 100644
index c063d7510f6..00000000000
--- a/angular/test/test-app/e2e/protractor.conf.js
+++ /dev/null
@@ -1,35 +0,0 @@
- // @ts-check
-// Protractor configuration file, see link for more information
-// https://github.com/angular/protractor/blob/master/lib/config.ts
-
-const { SpecReporter } = require('jasmine-spec-reporter');
-
-/**
- * @type { import("protractor").Config }
- */
-exports.config = {
- allScriptsTimeout: 11000,
- specs: [
- './src/**/*.e2e-spec.ts'
- ],
- capabilities: {
- 'browserName': 'chrome'
- },
- chromeOptions: {
- args: [ "--headless", "--disable-gpu", "--window-size=400,1000", "--start-maximized" ]
- },
- directConnect: true,
- baseUrl: 'http://localhost:4200/',
- framework: 'jasmine',
- jasmineNodeOpts: {
- showColors: true,
- defaultTimeoutInterval: 100000,
- print: function() {}
- },
- onPrepare() {
- require('ts-node').register({
- project: require('path').join(__dirname, './tsconfig.json')
- });
- jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
- }
-};
diff --git a/angular/test/test-app/e2e/src/form.e2e-spec.ts b/angular/test/test-app/e2e/src/form.e2e-spec.ts
deleted file mode 100644
index 3c26bd9d7ec..00000000000
--- a/angular/test/test-app/e2e/src/form.e2e-spec.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
-
-describe('form', () => {
-
- afterEach(() => {
- return handleErrorMessages();
- });
-
- describe('change', () => {
- beforeEach(async () => {
- await browser.get('/form');
- await waitTime(30);
- });
-
- it('should have default values', async () => {
- await testStatus('INVALID');
- expect(await getText('#submit')).toEqual('false');
- await testData({
- 'datetime': '2010-08-20',
- 'select': null,
- 'toggle': false,
- 'input': '',
- 'input2': 'Default Value',
- 'checkbox': false,
- 'range': 5
- });
- });
-
- it('should become valid', async () => {
- await setProperty('ion-input.required', 'value', 'Some value');
- await testStatus('INVALID');
- await setProperty('ion-select', 'value', 'nes');
- await testStatus('INVALID');
- await setProperty('ion-range', 'value', 40);
- await testStatus('VALID');
- await testData({
- 'datetime': '2010-08-20',
- 'select': 'nes',
- 'toggle': false,
- 'input': 'Some value',
- 'input2': 'Default Value',
- 'checkbox': false,
- 'range': 40
- });
- });
-
- it('ion-toggle should change', async () => {
- await element(by.css('form ion-toggle')).click();
- await testData({
- 'datetime': '2010-08-20',
- 'select': null,
- 'toggle': true,
- 'input': '',
- 'input2': 'Default Value',
- 'checkbox': false,
- 'range': 5
- });
- });
-
- it('ion-checkbox should change', async () => {
- await element(by.css('ion-checkbox')).click();
- await testData({
- 'datetime': '2010-08-20',
- 'select': null,
- 'toggle': false,
- 'input': '',
- 'input2': 'Default Value',
- 'checkbox': true,
- 'range': 5
- });
- });
-
- it('should submit', async () => {
- await element(by.css('#set-values')).click();
- await waitTime(100);
- await element(by.css('#submit-button')).click();
- expect(await getText('#submit')).toEqual('true');
- });
- });
-
- describe('blur', () => {
- beforeEach(async () => {
- await browser.get('/form#blur');
- await waitTime(30);
- });
-
- it('ion-toggle should change only after blur', async () => {
- await element(by.css('form ion-toggle')).click();
- await testData({
- 'datetime': '2010-08-20',
- 'select': null,
- 'toggle': false,
- 'input': '',
- 'input2': 'Default Value',
- 'checkbox': false,
- 'range': 5
- });
- await element(by.css('ion-checkbox')).click();
- await testData({
- 'datetime': '2010-08-20',
- 'select': null,
- 'toggle': true,
- 'input': '',
- 'input2': 'Default Value',
- 'checkbox': false,
- 'range': 5
- });
- });
- });
-});
-
-async function testStatus(status: string) {
- expect(await element(by.css('#status')).getText()).toEqual(status);
-}
-
-async function testData(data: any) {
- expect(JSON.parse(await element(by.css('#data')).getText())).toEqual(data);
-}
diff --git a/angular/test/test-app/e2e/src/inputs.e2e-spec.ts b/angular/test/test-app/e2e/src/inputs.e2e-spec.ts
deleted file mode 100644
index 38d070bf195..00000000000
--- a/angular/test/test-app/e2e/src/inputs.e2e-spec.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { getProperty, setProperty, handleErrorMessages, waitTime } from './utils';
-
-describe('inputs', () => {
-
- beforeEach(async () => {
- await browser.get('/inputs');
- await waitTime(30);
- });
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should have default value', async () => {
- expect(await getProperty('ion-checkbox', 'checked')).toEqual(true);
- expect(await getProperty('ion-toggle', 'checked')).toEqual(true);
- expect(await getProperty('ion-input', 'value')).toEqual('some text');
- expect(await getProperty('ion-datetime', 'value')).toEqual('1994-03-15');
- expect(await getProperty('ion-select', 'value')).toEqual('nes');
- expect(await getProperty('ion-range', 'value')).toEqual(10);
- });
-
- it('should have reset value', async () => {
- await element(by.css('#reset-button')).click();
-
- expect(await getProperty('ion-checkbox', 'checked')).toEqual(false);
- expect(await getProperty('ion-toggle', 'checked')).toEqual(false);
- expect(await getProperty('ion-input', 'value')).toEqual('');
- expect(await getProperty('ion-datetime', 'value')).toEqual('');
- expect(await getProperty('ion-select', 'value')).toEqual('');
- expect(await getProperty('ion-range', 'value')).toEqual(null);
- });
-
- it('should get some value', async () => {
- await element(by.css('#reset-button')).click();
- await element(by.css('#set-button')).click();
-
- expect(await getProperty('ion-checkbox', 'checked')).toEqual(true);
- expect(await getProperty('ion-toggle', 'checked')).toEqual(true);
- expect(await getProperty('ion-input', 'value')).toEqual('some text');
- expect(await getProperty('ion-datetime', 'value')).toEqual('1994-03-15');
- expect(await getProperty('ion-select', 'value')).toEqual('nes');
- expect(await getProperty('ion-range', 'value')).toEqual(10);
- });
-
- it('change values should update angular', async () => {
- await element(by.css('#reset-button')).click();
-
- await setProperty('ion-checkbox', 'checked', true);
- await setProperty('ion-toggle', 'checked', true);
- await setProperty('ion-input', 'value', 'hola');
- await setProperty('ion-datetime', 'value', '1996-03-15');
- await setProperty('ion-select', 'value', 'playstation');
- await setProperty('ion-range', 'value', 20);
-
- expect(await element(by.css('#checkbox-note')).getText()).toEqual('true');
- expect(await element(by.css('#toggle-note')).getText()).toEqual('true');
- expect(await element(by.css('#input-note')).getText()).toEqual('hola');
- expect(await element(by.css('#datetime-note')).getText()).toEqual('1996-03-15');
- expect(await element(by.css('#select-note')).getText()).toEqual('playstation');
- expect(await element(by.css('#range-note')).getText()).toEqual('20');
- });
-
- it('nested components should not interfere with NgModel', async () => {
- expect(await element(by.css('#range-note')).getText()).toEqual('10');
- await element(by.css('#nested-toggle')).click();
- expect(await element(by.css('#range-note')).getText()).toEqual('10');
- });
-});
diff --git a/angular/test/test-app/e2e/src/modal.e2e-spec.ts b/angular/test/test-app/e2e/src/modal.e2e-spec.ts
deleted file mode 100644
index 1c300b5270f..00000000000
--- a/angular/test/test-app/e2e/src/modal.e2e-spec.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { waitTime, getText, handleErrorMessages } from './utils';
-
-describe('modals', () => {
-
- beforeEach(async () => {
- await browser.get('/modals');
- await waitTime(30);
- });
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should open standalone modal and close', async () => {
- await element(by.css('#action-button')).click();
-
- await waitTime(800);
-
- const modal = element(by.css('app-modal-example'));
- expect(await modal.$('h2').getText()).toEqual('123');
- expect(await modal.$('h3').getText()).toEqual('321');
-
- expect(await getText('#onWillDismiss')).toEqual('false');
- expect(await getText('#onDidDismiss')).toEqual('false');
-
- await modal.$('#close-modal').click();
- await waitTime(800);
-
- expect(await getText('#onWillDismiss')).toEqual('true');
- expect(await getText('#onDidDismiss')).toEqual('true');
- });
-
- it('should open nav modal and close', async () => {
- await element(by.css('#action-button-2')).click();
-
- await waitTime(800);
-
- let page = element(by.css('ion-nav > *:last-child'));
- expect(await page.$('h2').getText()).toEqual('123');
- expect(await page.$('h3').getText()).toEqual('321');
-
- await page.$('.push-page').click();
- await waitTime(800);
-
- page = element(by.css('ion-nav > *:last-child'));
- expect(await page.$('h2').getText()).toEqual('pushed!');
- expect(await page.$('h3').getText()).toEqual('');
-
- await page.$('.pop-page').click();
- await waitTime(800);
-
- page = element(by.css('ion-nav > *:last-child'));
- expect(await page.$('h2').getText()).toEqual('123');
- });
-});
diff --git a/angular/test/test-app/e2e/src/navigation.e2e-spec.ts b/angular/test/test-app/e2e/src/navigation.e2e-spec.ts
deleted file mode 100644
index effa28fcb49..00000000000
--- a/angular/test/test-app/e2e/src/navigation.e2e-spec.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { handleErrorMessages, waitTime, testStack } from './utils';
-
-describe('navigation', () => {
-
- afterEach(() => {
- return handleErrorMessages();
- });
-
- // TODO: Fix flaky tests
- xit ('should swipe and abort', async () => {
- await browser.get('/router-link?ionic:mode=ios');
- await waitTime(500);
- await element(by.css('#routerLink')).click();
- await waitTime(500);
- await swipeLeft(5);
- await waitTime(500);
-
- const pageHidden = element(by.css('app-router-link'));
- expect(await pageHidden.getAttribute('aria-hidden')).toEqual('true');
- expect(await pageHidden.getAttribute('class')).toEqual('ion-page ion-page-hidden');
-
- const pageVisible = element(by.css('app-router-link-page'));
- expect(await pageVisible.getAttribute('aria-hidden')).toEqual(null);
- expect(await pageVisible.getAttribute('class')).toEqual('ion-page can-go-back');
- });
-
- xit ('should swipe and go back', async () => {
- await browser.get('/router-link?ionic:mode=ios');
- await waitTime(500);
- await element(by.css('#routerLink')).click();
- await waitTime(500);
- await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
-
- await swipeLeft(300);
-
- await waitTime(1000);
- await testStack('ion-router-outlet', ['app-router-link']);
-
- const page = element(by.css('app-router-link'));
- expect(await page.getAttribute('aria-hidden')).toEqual(null);
- expect(await page.getAttribute('class')).toEqual('ion-page');
- })
-
- it('should navigate correctly', async () => {
- await browser.get('/navigation/page1');
- await waitTime(2000);
- await testStack('ion-router-outlet', ['app-navigation-page2', 'app-navigation-page1']);
-
- const pageHidden = element(by.css('app-navigation-page2'));
- expect(await pageHidden.getAttribute('aria-hidden')).toEqual('true');
- expect(await pageHidden.getAttribute('class')).toEqual('ion-page ion-page-hidden');
-
- const pageVisible = element(by.css('app-navigation-page1'));
- expect(await pageVisible.getAttribute('aria-hidden')).toEqual(null);
- expect(await pageVisible.getAttribute('class')).toEqual('ion-page can-go-back');
- });
-
-});
-
-function swipeLeft(end: number) {
- return browser.driver.touchActions()
- .tapAndHold({x: 5, y: 1})
- .move({x: 6, y: 1})
- .move({x: 7, y: 1})
- .move({x: 8, y: 1})
- .move({x: 30, y: 1})
- .move({x: 300, y: 1})
- .move({x: end, y: 1})
- .move({x: end, y: 1})
- .release({x: end, y: 1})
- .perform();
-}
\ No newline at end of file
diff --git a/angular/test/test-app/e2e/src/nested-outlet.e2e-spec.ts b/angular/test/test-app/e2e/src/nested-outlet.e2e-spec.ts
deleted file mode 100644
index b7c2c2b6e20..00000000000
--- a/angular/test/test-app/e2e/src/nested-outlet.e2e-spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { waitTime, handleErrorMessages, goBack } from './utils';
-
-describe('nested-outlet', () => {
-
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should navigate correctly', async () => {
- await browser.get('/nested-outlet/page');
- expect(await element(by.css('ion-router-outlet ion-router-outlet app-nested-outlet-page h1')).getText()).toEqual('Nested page 1');
-
- await element(by.css('#goto-tabs')).click();
- await waitTime(500);
- await element(by.css('#goto-nested-page1')).click();
- await waitTime(500);
- await element(by.css('#goto-nested-page2')).click();
- await waitTime(500);
- expect(await element(by.css('ion-router-outlet ion-router-outlet app-nested-outlet-page2 h1')).getText()).toEqual('Nested page 2');
- });
-});
-
diff --git a/angular/test/test-app/e2e/src/providers.e2e-spec.ts b/angular/test/test-app/e2e/src/providers.e2e-spec.ts
deleted file mode 100644
index 3a3e0a4b30f..00000000000
--- a/angular/test/test-app/e2e/src/providers.e2e-spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { handleErrorMessages, waitTime } from './utils';
-
-describe('providers', () => {
-
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should load all providers', async () => {
- await browser.get('/providers');
-
- expect(await element(by.css('#is-loaded')).getText()).toEqual('true');
- expect(await element(by.css('#is-ready')).getText()).toEqual('true');
- expect(await element(by.css('#is-paused')).getText()).toEqual('true');
- expect(await element(by.css('#is-resumed')).getText()).toEqual('true');
- expect(await element(by.css('#is-resized')).getText()).toEqual('true');
- expect(await element(by.css('#is-testing')).getText()).toEqual('false');
- expect(await element(by.css('#is-desktop')).getText()).toEqual('true');
- expect(await element(by.css('#is-mobile')).getText()).toEqual('false');
- expect(await element(by.css('#keyboard-height')).getText()).toEqual('12345');
- });
-
- it('should detect testing mode', async () => {
- await browser.get('/providers?ionic:_testing=true');
-
- expect(await element(by.css('#is-testing')).getText()).toEqual('true');
- });
-});
diff --git a/angular/test/test-app/e2e/src/router-link.e2e-spec.ts b/angular/test/test-app/e2e/src/router-link.e2e-spec.ts
deleted file mode 100644
index 20fcbb23cfa..00000000000
--- a/angular/test/test-app/e2e/src/router-link.e2e-spec.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import { browser, element, by, protractor } from 'protractor';
-import { waitTime, testStack, testLifeCycle, handleErrorMessages, getText } from './utils';
-
-const EC = protractor.ExpectedConditions;
-
-describe('router-link params and fragments', () => {
- const queryParam = 'A&=#Y';
- const fragment = 'myDiv1';
- const id = 'MyPageID==';
-
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should go to a page with properly encoded values', async () => {
- await browser.get('/router-link?ionic:_testing=true');
- await element(by.css('#queryParamsFragment')).click();
-
- const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
-
- browser.wait(EC.urlContains(expectedRoute), 5000);
- });
-
- it('should return to a page with preserved query param and fragment', async () => {
- await browser.get('/router-link?ionic:_testing=true');
- await waitTime(30);
- await element(by.css('#queryParamsFragment')).click();
- await waitTime(400);
- await element(by.css('#goToPage3')).click();
-
- browser.wait(EC.urlContains('router-link-page3'), 5000);
- await waitTime(400);
-
- await element(by.css('#goBackFromPage3')).click();
-
- const expectedRoute = `${encodeURIComponent(id)}?token=${encodeURIComponent(queryParam)}#${encodeURIComponent(fragment)}`;
- browser.wait(EC.urlContains(expectedRoute), 5000);
- });
-
- it('should preserve query param and fragment with defaultHref string', async () => {
- await browser.get('/router-link-page3?ionic:_testing=true');
- await waitTime(30);
-
- await element(by.css('#goBackFromPage3')).click();
-
- const expectedRoute = '?token=ABC#fragment';
- browser.wait(EC.urlContains(expectedRoute), 5000);
- });
-});
-
-describe('router-link', () => {
-
- beforeEach(async () => {
- await browser.get('/router-link');
- await waitTime(30);
- });
- afterEach(() => {
- return handleErrorMessages();
- });
-
-
- it('should have correct lifecycle counts', async () => {
- await testLifeCycle('app-router-link', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
- });
-
- describe('forward', () => {
-
- it('should go forward with ion-button[routerLink]', async () => {
- await element(by.css('#routerLink')).click();
- await testForward();
- });
-
- it('should go forward with a[routerLink]', async () => {
- await element(by.css('#a')).click();
- await testForward();
- });
-
- it('should go forward with button + navigateByUrl()', async () => {
- await element(by.css('#button')).click();
- await testForward();
- });
-
- it('should go forward with button + navigateForward()', async () => {
- await element(by.css('#button-forward')).click();
- await testForward();
- });
- });
-
- describe('root', () => {
-
- it('should go root with ion-button[routerLink][routerDirection=root]', async () => {
- await element(by.css('#routerLink-root')).click();
- await testRoot();
- });
-
- it('should go root with a[routerLink][routerDirection=root]', async () => {
- await element(by.css('#a-root')).click();
- await testRoot();
- });
-
- it('should go root with button + navigateRoot', async () => {
- await element(by.css('#button-root')).click();
- await testRoot();
- });
- });
-
- describe('back', () => {
-
- it('should go back with ion-button[routerLink][routerDirection=back]', async () => {
- await element(by.css('#routerLink-back')).click();
- });
-
- it('should go back with a[routerLink][routerDirection=back]', async () => {
- await element(by.css('#a-back')).click();
- await testBack();
- });
-
- it('should go back with button + navigateBack', async () => {
- await element(by.css('#button-back')).click();
- await testBack();
- });
- });
-});
-
-async function testForward() {
- await waitTime(2500);
- await testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
- await testLifeCycle('app-router-link-page', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
- expect(await getText(`app-router-link-page #canGoBack`)).toEqual('true');
-
- await browser.navigate().back();
- await waitTime(100);
- await testStack('ion-router-outlet', ['app-router-link']);
- await testLifeCycle('app-router-link', {
- ionViewWillEnter: 2,
- ionViewDidEnter: 2,
- ionViewWillLeave: 1,
- ionViewDidLeave: 1,
- });
-}
-
-async function testRoot() {
- await waitTime(200);
- await testStack('ion-router-outlet', ['app-router-link-page']);
- await testLifeCycle('app-router-link-page', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
- expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
-
- await browser.navigate().back();
- await waitTime(100);
- await testStack('ion-router-outlet', ['app-router-link']);
- await testLifeCycle('app-router-link', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
-}
-
-async function testBack() {
- await waitTime(500);
- await testStack('ion-router-outlet', ['app-router-link-page']);
- await testLifeCycle('app-router-link-page', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
- expect(await getText(`app-router-link-page #canGoBack`)).toEqual('false');
-
- await browser.navigate().back();
- await waitTime(100);
- await testStack('ion-router-outlet', ['app-router-link']);
- await testLifeCycle('app-router-link', {
- ionViewWillEnter: 1,
- ionViewDidEnter: 1,
- ionViewWillLeave: 0,
- ionViewDidLeave: 0,
- });
-}
diff --git a/angular/test/test-app/e2e/src/slides.e2e-spec.ts b/angular/test/test-app/e2e/src/slides.e2e-spec.ts
deleted file mode 100644
index 3e715f4e692..00000000000
--- a/angular/test/test-app/e2e/src/slides.e2e-spec.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { handleErrorMessages, waitTime } from './utils';
-
-describe('slides', () => {
-
- beforeEach(async () => {
- await browser.get('/slides');
- await waitTime(30);
- });
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should change index on slide change', async () => {
- expect(await element.all(by.css('ion-slide')).count()).toEqual(0);
- await addSlides();
- expect(await element.all(by.css('ion-slide')).count()).toEqual(3);
-
- await checkIndex('0');
-
- await nextSlide();
- await checkIndex('1');
-
- await nextSlide();
- await checkIndex('2');
-
- await prevSlide();
- await checkIndex('1');
- });
-});
-
-async function checkIndex(index: string) {
- expect(await element(by.css('#slide-index')).getText()).toEqual(index);
- expect(await element(by.css('#slide-index-2')).getText()).toEqual(index);
-}
-
-async function addSlides() {
- await element(by.css('#add-slides')).click();
- await waitTime(800);
-}
-
-
-async function nextSlide() {
- await element(by.css('#btn-next')).click();
- await waitTime(800);
-}
-
-async function prevSlide() {
- await element(by.css('#btn-prev')).click();
- await waitTime(800);
-}
diff --git a/angular/test/test-app/e2e/src/tabs.e2e-spec.ts b/angular/test/test-app/e2e/src/tabs.e2e-spec.ts
deleted file mode 100644
index 0f8d6063d6d..00000000000
--- a/angular/test/test-app/e2e/src/tabs.e2e-spec.ts
+++ /dev/null
@@ -1,334 +0,0 @@
-import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor';
-import { handleErrorMessages, testStack, waitTime } from './utils';
-
-describe('tabs', () => {
- afterEach(() => {
- return handleErrorMessages();
- });
- describe('entry url - /tabs', () => {
- beforeEach(async () => {
- await browser.get('/tabs');
- await waitTime(30);
- });
-
- it('should redirect and load tab-account', async () => {
- await testTabTitle('Tab 1 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1']);
- await testState(1, 'account');
- });
-
- it('should navigate between tabs and ionChange events should be dispatched ', async () => {
- let tab = await testTabTitle('Tab 1 - Page 1');
- expect(await tab.$('.segment-changed').getText()).toEqual('false');
-
- await element(by.css('#tab-button-contact')).click();
- tab = await testTabTitle('Tab 2 - Page 1');
- expect(await tab.$('.segment-changed').getText()).toEqual('false');
- });
-
- it('should simulate stack + double tab click', async () => {
- let tab = await getSelectedTab() as ElementFinder;
- await tab.$('#goto-tab1-page2').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']);
- await testState(1, 'account');
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
-
- await element(by.css('#tab-button-contact')).click();
- await testTabTitle('Tab 2 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
- await testState(2, 'contact');
-
- await element(by.css('#tab-button-account')).click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
- await testState(3, 'account');
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
- await testState(3, 'account');
- });
-
- it('should simulate stack + back button click', async () => {
- const tab = await getSelectedTab();
- await tab.$('#goto-tab1-page2').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testState(1, 'account');
-
- await element(by.css('#tab-button-contact')).click();
- await testTabTitle('Tab 2 - Page 1');
- await testState(2, 'contact');
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testState(3, 'account');
-
- await element(by.css('ion-back-button')).click();
- await testTabTitle('Tab 1 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
- await testState(3, 'account');
- });
-
- it('should navigate deep then go home', async () => {
- let tab = await getSelectedTab();
- await tab.$('#goto-tab1-page2').click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
-
- await tab.$('#goto-next').click();
- tab = await testTabTitle('Tab 1 - Page 2 (2)');
-
- await element(by.css('#tab-button-contact')).click();
- tab = await testTabTitle('Tab 2 - Page 1');
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 2 (2)');
- await testStack('ion-tabs ion-router-outlet', [
- 'app-tabs-tab1',
- 'app-tabs-tab1-nested',
- 'app-tabs-tab1-nested',
- 'app-tabs-tab2'
- ]);
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
- await testStack('ion-tabs ion-router-outlet', [
- 'app-tabs-tab1',
- 'app-tabs-tab2'
- ]);
- });
-
- it('should switch tabs and go back', async () => {
- await element(by.css('#tab-button-contact')).click();
- const tab = await testTabTitle('Tab 2 - Page 1');
-
- await tab.$('#goto-tab1-page1').click();
- await testTabTitle('Tab 1 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
- });
-
- it('should switch tabs and go to nested', async () => {
- await element(by.css('#tab-button-contact')).click();
- const tab = await testTabTitle('Tab 2 - Page 1');
-
- await tab.$('#goto-tab1-page2').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']);
- });
-
- it('should load lazy loaded tab', async () => {
- await element(by.css('#tab-button-lazy')).click();
- await testTabTitle('Tab 3 - Page 1');
- });
-
- it('should use ion-back-button defaultHref', async () => {
- let tab = await getSelectedTab() as ElementFinder;
- await tab.$('#goto-tab3-page2').click();
- tab = await testTabTitle('Tab 3 - Page 2');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3-nested']);
-
- await tab.$('ion-back-button').click();
- await testTabTitle('Tab 3 - Page 1');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3']);
- });
-
- it('should preserve navigation extras when switching tabs', async () => {
- const expectUrlToContain = 'search=hello#fragment';
- let tab = await getSelectedTab() as ElementFinder;
- await tab.$('#goto-nested-page1-with-query-params').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testUrlContains(expectUrlToContain);
-
- await element(by.css('#tab-button-contact')).click();
- await testTabTitle('Tab 2 - Page 1');
-
- await element(by.css('#tab-button-account')).click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
- await testUrlContains(expectUrlToContain);
- });
-
- it('should set root when clicking on an active tab to navigate to the root', async () => {
- const expectNestedTabUrlToContain = 'search=hello#fragment';
- let tab = await getSelectedTab() as ElementFinder;
- const initialUrl = await browser.getCurrentUrl();
- await tab.$('#goto-nested-page1-with-query-params').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testUrlContains(expectNestedTabUrlToContain);
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
-
- await testUrlEquals(initialUrl);
- });
-
- });
-
- describe('entry tab contains navigation extras', () => {
- const expectNestedTabUrlToContain = 'search=hello#fragment';
- const rootUrlParams = 'test=123#rootFragment';
- const rootUrl = `/tabs/account?${rootUrlParams}`;
-
- beforeEach(async () => {
- await browser.get(rootUrl);
- await waitTime(30);
- });
-
- it('should preserve root url navigation extras when clicking on an active tab to navigate to the root', async () => {
- await browser.get(rootUrl);
-
- let tab = await getSelectedTab() as ElementFinder;
- await tab.$('#goto-nested-page1-with-query-params').click();
- await testTabTitle('Tab 1 - Page 2 (1)');
- await testUrlContains(expectNestedTabUrlToContain);
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
-
- await testUrlContains(rootUrl);
- });
-
- it('should preserve root url navigation extras when changing tabs', async () => {
- await browser.get(rootUrl);
-
- let tab = await getSelectedTab() as ElementFinder;
- await element(by.css('#tab-button-contact')).click();
- tab = await testTabTitle('Tab 2 - Page 1');
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
-
- await testUrlContains(rootUrl);
- });
-
- it('should navigate deep then go home and preserve navigation extras', async () => {
- let tab = await getSelectedTab();
- await tab.$('#goto-tab1-page2').click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
-
- await tab.$('#goto-next').click();
- tab = await testTabTitle('Tab 1 - Page 2 (2)');
-
- await element(by.css('#tab-button-contact')).click();
- tab = await testTabTitle('Tab 2 - Page 1');
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 2 (2)');
-
- await element(by.css('#tab-button-account')).click();
- await testTabTitle('Tab 1 - Page 1');
-
- await testUrlContains(rootUrl);
- });
- });
-
- describe('entry url - /tabs/account/nested/1', () => {
- beforeEach(async () => {
- await browser.get('/tabs/account/nested/1');
- await waitTime(30);
- });
-
- it('should only display the back-button when there is a page in the stack', async () => {
- let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
-
- await element(by.css('#tab-button-account')).click();
- tab = await testTabTitle('Tab 1 - Page 1');
-
- await tab.$('#goto-tab1-page2').click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
- });
-
- it('should not reuse the same page', async () => {
- let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
- await tab.$('#goto-next').click();
- tab = await testTabTitle('Tab 1 - Page 2 (2)');
- await tab.$('#goto-next').click();
- tab = await testTabTitle('Tab 1 - Page 2 (3)');
-
- await testStack('ion-tabs ion-router-outlet', [
- 'app-tabs-tab1-nested',
- 'app-tabs-tab1-nested',
- 'app-tabs-tab1-nested'
- ]);
-
- await tab.$('ion-back-button').click();
- tab = await testTabTitle('Tab 1 - Page 2 (2)');
- await tab.$('ion-back-button').click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
-
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
-
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
- });
- });
-
- describe('entry url - /tabs/lazy', () => {
- beforeEach(async () => {
- await browser.get('/tabs/lazy');
- await waitTime(30);
- });
-
- it('should not display the back-button if coming from a different stack', async () => {
- let tab = await testTabTitle('Tab 3 - Page 1') as ElementFinder;
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']);
-
- await tab.$('#goto-tab1-page2').click();
- tab = await testTabTitle('Tab 1 - Page 2 (1)');
- await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']);
- expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
- });
- });
-
- describe('enter url - /tabs/contact/one', () => {
- beforeEach(async () => {
- await browser.get('/tabs/contact/one');
- await waitTime(30);
- });
-
- it('should return to correct tab after going to page in different outlet', async () => {
- const tab = await getSelectedTab();
- await tab.$('#goto-nested-page1').click();
-
- await waitTime(600);
- await testStack('app-nested-outlet ion-router-outlet', ['app-nested-outlet-page']);
-
- const nestedOutlet = await element(by.css('app-nested-outlet'));
- const backButton = await nestedOutlet.$('ion-back-button');
- await backButton.click();
-
- await testTabTitle('Tab 2 - Page 1');
- });
- })
-});
-
-async function testState(count: number, tab: string) {
- expect(await element(by.css('#tabs-state')).getText()).toEqual(`${count}.${tab}`);
-}
-
-async function testTabTitle(title: string) {
- await waitTime(1000);
- const tab = await getSelectedTab();
- expect(await tab.$('ion-title').getText()).toEqual(title);
- return tab;
-}
-
-async function testUrlContains(urlFragment: string) {
- await browser.wait(ExpectedConditions.urlContains(urlFragment),
- 5000,
- `expected ${browser.getCurrentUrl()} to contain ${urlFragment}`);
-}
-
-async function testUrlEquals(url: string) {
- await browser.wait(ExpectedConditions.urlIs(url),
- 5000,
- `expected ${browser.getCurrentUrl()} to equal ${url}`);
-}
-
-async function getSelectedTab(): Promise {
- const tabs = element.all(by.css('ion-tabs ion-router-outlet > *:not(.ion-page-hidden)'));
- expect(await tabs.count()).toEqual(1);
- const tab = tabs.first();
- return tab;
-}
diff --git a/angular/test/test-app/e2e/src/utils.ts b/angular/test/test-app/e2e/src/utils.ts
deleted file mode 100644
index cc85e9ab6ca..00000000000
--- a/angular/test/test-app/e2e/src/utils.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { browser } from 'protractor';
-
-export function goBack() {
- return browser.executeScript(`return window.history.back()`);
-}
-
-export function getProperty(selector: string, property: string) {
- return browser.executeScript(`
- return document.querySelector('${selector}')['${property}'];
- `);
-}
-
-export function getText(selector: string) {
- return browser.executeScript(`
- return document.querySelector('${selector}').textContent;
- `);
-}
-
-export function setProperty(selector: string, property: string, value: any) {
- const text = JSON.stringify(value);
- return browser.executeScript(`
- document.querySelector('${selector}')['${property}'] = ${text};
- `);
-}
-
-export function waitTime(time: number) {
- return new Promise(resolve => {
- setTimeout(resolve, time);
- });
-}
-
-export interface LifeCycleCount {
- ionViewWillEnter: number;
- ionViewDidEnter: number;
- ionViewWillLeave: number;
- ionViewDidLeave: number;
-}
-
-export function handleErrorMessages() {
- return browser.manage().logs().get('browser').then(function (browserLog) {
- for (let i = 0; i <= browserLog.length - 1; i++) {
- if (browserLog[i].level.name_ === 'SEVERE') {
- fail(browserLog[i].message);
- }
- }
- });
-}
-
-export async function testLifeCycle(selector: string, expected: LifeCycleCount) {
- await waitTime(50);
- const results = await Promise.all([
- getText(`${selector} #ngOnInit`),
- getText(`${selector} #ionViewWillEnter`),
- getText(`${selector} #ionViewDidEnter`),
- getText(`${selector} #ionViewWillLeave`),
- getText(`${selector} #ionViewDidLeave`),
- ]);
-
- expect(results[0]).toEqual('1');
- expect(results[1]).toEqual(expected.ionViewWillEnter.toString());
- expect(results[2]).toEqual(expected.ionViewDidEnter.toString());
- expect(results[3]).toEqual(expected.ionViewWillLeave.toString());
- expect(results[4]).toEqual(expected.ionViewDidLeave.toString());
-}
-
-export async function testStack(selector: string, expected: string[]) {
- const children = await browser.executeScript(`
- return Array.from(
- document.querySelector('${selector}').children
- ).map(el => el.tagName.toLowerCase());
- `);
- expect(children).toEqual(expected);
-}
diff --git a/angular/test/test-app/e2e/src/view-child.e2e-spec.ts b/angular/test/test-app/e2e/src/view-child.e2e-spec.ts
deleted file mode 100644
index 28a49646a20..00000000000
--- a/angular/test/test-app/e2e/src/view-child.e2e-spec.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { handleErrorMessages, waitTime } from './utils';
-
-describe('view-child', () => {
-
- beforeEach(async () => {
- await browser.get('/view-child');
- await waitTime(30);
- });
- afterEach(() => {
- return handleErrorMessages();
- });
-
- it('should get a reference to all children', async () => {
- // button should be red
- expect(await element(by.css('#color-button.ion-color-danger')).isPresent()).toBeTruthy();
-
- // tabs should be found
- expect(await element(by.css('#tabs-result')).getText()).toEqual('all found');
- });
-
-});
diff --git a/angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts b/angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
deleted file mode 100644
index 70e591904b6..00000000000
--- a/angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { browser, element, by } from 'protractor';
-import { waitTime, handleErrorMessages } from './utils';
-
-describe('virtual-scroll', () => {
- afterEach(() => {
- return handleErrorMessages();
- });
- beforeEach(async () => {
- await browser.get('/virtual-scroll');
- await waitTime(30);
- });
-
- it('should open virtual-scroll', () => {
- const virtualElements = element.all(by.css('ion-virtual-scroll > *'));
- expect(virtualElements.count()).toBeGreaterThan(0);
- });
-
-});
diff --git a/angular/test/test-app/e2e/tsconfig.json b/angular/test/test-app/e2e/tsconfig.json
deleted file mode 100644
index 28ffa11a54d..00000000000
--- a/angular/test/test-app/e2e/tsconfig.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "angularCompilerOptions": {
- "fullTemplateTypeCheck": true,
- "strictMetadataEmit" : true
- },
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "outDir": "../out-tsc/app",
- "module": "commonjs",
- "target": "es5",
- "types": [
- "jasmine",
- "jasminewd2",
- "node"
- ]
- }
-}
\ No newline at end of file
diff --git a/angular/test/test-app/karma.conf.js b/angular/test/test-app/karma.conf.js
deleted file mode 100644
index af072fc954a..00000000000
--- a/angular/test/test-app/karma.conf.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// Karma configuration file, see link for more information
-// https://karma-runner.github.io/1.0/config/configuration-file.html
-
-module.exports = function (config) {
- config.set({
- basePath: '',
- frameworks: ['jasmine', '@angular-devkit/build-angular'],
- 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: {
- clearContext: false // leave Jasmine Spec Runner output visible in browser
- },
- coverageIstanbulReporter: {
- dir: require('path').join(__dirname, '../coverage'),
- reports: ['html', 'lcovonly', 'text-summary'],
- fixWebpackSourcePaths: true
- },
- reporters: ['progress', 'kjhtml'],
- port: 9876,
- colors: true,
- logLevel: config.LOG_INFO,
- autoWatch: true,
- browsers: ['Chrome'],
- singleRun: false,
- restartOnFileChange: true
- });
-};
diff --git a/angular/test/test-app/package.json b/angular/test/test-app/package.json
deleted file mode 100644
index 5299f995b7a..00000000000
--- a/angular/test/test-app/package.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "name": "ionic-angular-test-app",
- "version": "0.0.0",
- "private": true,
- "scripts": {
- "ng": "ng",
- "start": "npm run sync && ng serve",
- "sync:build": "sh scripts/build-ionic.sh",
- "sync": "sh scripts/sync.sh",
- "build": "npm run sync && ng build --prod --no-progress",
- "test": "ng e2e --prod",
- "test.dev": "npm run sync && ng e2e",
- "lint": "ng lint",
- "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": "^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": "9.0.0-next.9",
- "core-js": "^2.6.2",
- "express": "^4.15.2",
- "rxjs": "^6.5.3",
- "tslib": "^1.10.0",
- "zone.js": "~0.10.2"
- },
- "devDependencies": {
- "@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.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-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.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
deleted file mode 100644
index c71695a7234..00000000000
--- a/angular/test/test-app/scripts/sync.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copy angular dist
-rm -rf node_modules/@ionic/angular
-cp -a ../../dist node_modules/@ionic/angular
-
-# Copy angular server
-rm -rf node_modules/@ionic/angular-server
-cp -a ../../../packages/angular-server/dist node_modules/@ionic/angular-server
-
-# # Copy core dist
-rm -rf node_modules/@ionic/core
-mkdir node_modules/@ionic/core
-cp -a ../../../core/css node_modules/@ionic/core/css
-cp -a ../../../core/dist node_modules/@ionic/core/dist
-cp -a ../../../core/hydrate node_modules/@ionic/core/hydrate
-cp -a ../../../core/loader node_modules/@ionic/core/loader
-cp -a ../../../core/package.json node_modules/@ionic/core/package.json
-
-# # Copy ionicons
-rm -rf node_modules/ionicons
-cp -a ../../../core/node_modules/ionicons node_modules/ionicons
diff --git a/angular/test/test-app/src/app/alert/alert.component.html b/angular/test/test-app/src/app/alert/alert.component.html
deleted file mode 100644
index e3e40fc6921..00000000000
--- a/angular/test/test-app/src/app/alert/alert.component.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-