Compare commits

..

12 Commits

Author SHA1 Message Date
Liam DeBeasi
12c1093219 5.5.5 2021-02-26 13:19:24 -05:00
Liam DeBeasi
4d058f0a2a Merge branch 'release-5.5.5' of https://github.com/ionic-team/ionic-framework into release-5.5.5 2021-02-26 13:04:02 -05:00
Liam DeBeasi
7dd2e6d287 fix(vue): account for event name changes in vue 3.0.6+ (#22980)
resolves #22977
2021-02-26 13:03:45 -05:00
Liam DeBeasi
8b57bfd8da build 2021-02-26 12:49:37 -05:00
Liam DeBeasi
0dce02f4da update 2021-02-26 12:39:37 -05:00
Liam DeBeasi
5c11a4e3e7 fix: 2021-02-26 12:25:30 -05:00
Liam DeBeasi
031dde7a90 bump 2021-02-26 12:13:36 -05:00
Liam DeBeasi
13bcb15860 add fix 2021-02-26 10:53:03 -05:00
Liam DeBeasi
7b160e6263 merge release-5.5.4
Release 5.5.4
2021-02-04 11:50:59 -05:00
Liam DeBeasi
c3f7ecb63d merge release-5.5.3
Release 5.5.3
2021-01-28 12:38:18 -05:00
Liam DeBeasi
f5844e5e05 merge release-5.5.2
Release 5.5.2
2020-12-09 16:04:01 -05:00
Liam DeBeasi
e5757fc99b merge release-5.5.1
Release 5.5.1
2020-11-25 18:26:13 -05:00
436 changed files with 37283 additions and 93012 deletions

View File

@@ -1,32 +1,30 @@
version: 2.1
orbs:
cypress: cypress-io/cypress@1.27.0
aliases:
- &restore-cache
keys:
- dependency-cache-{{ checksum "package.json" }}-7
- dependency-cache-{{ checksum "package.json" }}-3
- &save-cache
key: dependency-cache-{{ checksum "package.json" }}-7
key: dependency-cache-{{ checksum "package.json" }}-3
paths:
- node_modules
- &restore-cache-core
keys:
- dependency-cache-{{ checksum "core/package.json" }}-7
- dependency-cache-{{ checksum "core/package.json" }}-3
- &save-cache-core
key: dependency-cache-{{ checksum "core/package.json" }}-7
key: dependency-cache-{{ checksum "core/package.json" }}-3
paths:
- core/node_modules
- &restore-cache-core-stencil
keys:
- stencil-cache-6
- stencil-cache-2
- &save-cache-core-stencil
key: stencil-cache-6
key: stencil-cache-2
paths:
- core/.stencil
- core/screenshot/images
@@ -66,7 +64,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- node_modules
- "*"
build-core:
<<: *defaults
@@ -87,12 +85,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- core/node_modules
- core/dist
- core/components
- core/css
- core/hydrate
- core/loader
- "*"
build-angular:
<<: *defaults
@@ -115,8 +108,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- angular/node_modules
- angular/dist
- "*"
build-angular-server:
<<: *defaults
@@ -133,7 +125,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/angular-server/dist
- "*"
build-react:
<<: *defaults
@@ -156,10 +148,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/react/node_modules
- packages/react/dist
- packages/react/css
- "*"
build-react-router:
<<: *defaults
steps:
@@ -187,8 +176,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/react-router/node_modules
- packages/react-router/dist
- "*"
build-vue:
<<: *defaults
@@ -211,9 +199,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/vue/node_modules
- packages/vue/dist
- packages/vue/css
- "*"
build-vue-router:
<<: *defaults
@@ -236,7 +222,7 @@ jobs:
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/vue-router/dist
- "*"
test-core-clean-build:
<<: *defaults
@@ -266,7 +252,7 @@ jobs:
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run test.e2e -- --ci --no-build
command: npm run test.e2e --ci
working_directory: /tmp/workspace/core
test-core-spec:
@@ -276,7 +262,7 @@ jobs:
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run test.spec -- --ci
command: npm run test.spec --ci
working_directory: /tmp/workspace/core
test-core-treeshake:
@@ -286,7 +272,7 @@ jobs:
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run test.treeshake -- --ci
command: npm run test.treeshake --ci
working_directory: /tmp/workspace/core
test-core-screenshot:
@@ -297,7 +283,7 @@ jobs:
at: /tmp/workspace
- run:
name: Run Screenshot
command: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci --no-build || true
command: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci || true
working_directory: /tmp/workspace/core
test-core-screenshot-master:
@@ -308,7 +294,7 @@ jobs:
at: /tmp/workspace
- run:
name: Run Screenshot
command: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci --update-screenshot --no-build || true
command: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci --update-screenshot || true
working_directory: /tmp/workspace/core
test-angular-lint:
@@ -399,33 +385,6 @@ jobs:
command: npm run test.spec
working_directory: /tmp/workspace/packages/react-router
install-react-test-app:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
command: CYPRESS_CACHE_FOLDER=/tmp/workspace/packages/react-router/test-app npm install
working_directory: /tmp/workspace/packages/react-router/test-app
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/react-router/test-app
test-react-e2e:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run sync
working_directory: /tmp/workspace/packages/react-router/test-app
- run:
command: CYPRESS_CACHE_FOLDER=/tmp/workspace/packages/react-router/test-app npm run e2e
working_directory: /tmp/workspace/packages/react-router/test-app
test-vue-router-spec:
<<: *defaults
steps:
@@ -458,39 +417,9 @@ jobs:
command: npm install --legacy-peer-deps
working_directory: /tmp/workspace/angular/test/test-app
- run:
command: npm run test
command: npm run test -- --protractor-config=e2e/protractor-ci.conf.js
working_directory: /tmp/workspace/angular/test/test-app
install-vue-test-app:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
command: CYPRESS_CACHE_FOLDER=/tmp/workspace/packages/vue/test-app npm install
working_directory: /tmp/workspace/packages/vue/test-app
- persist_to_workspace:
root: /tmp/workspace
paths:
- packages/vue/test-app
test-vue-spec-and-e2e:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
command: npm run sync
working_directory: /tmp/workspace/packages/vue/test-app
- run:
command: npm run test:unit
working_directory: /tmp/workspace/packages/vue/test-app
- run:
command: CYPRESS_CACHE_FOLDER=/tmp/workspace/packages/vue/test-app npm run test:e2e
working_directory: /tmp/workspace/packages/vue/test-app
workflows:
version: 2
build:
@@ -539,24 +468,16 @@ workflows:
requires: [build-react]
- test-react-router-spec:
requires: [build-react-router]
- install-react-test-app:
requires: [build-core]
- test-react-e2e:
requires: [install-react-test-app, build-react, build-react-router]
- build-vue:
requires: [build-core]
- build-vue-router:
requires: [build-vue]
requires: [build-core, build-vue]
- test-vue-lint:
requires: [build-vue]
- test-vue-router-lint:
requires: [build-vue-router]
- test-vue-router-spec:
requires: [build-vue-router]
- install-vue-test-app:
requires: [build-core]
- test-vue-spec-and-e2e:
requires: [install-vue-test-app, build-vue, build-vue-router]
- test-angular-lint:
requires: [build-angular]
- test-angular-e2e:

View File

@@ -11,12 +11,10 @@
* [References](#references)
- [Accessibility](#accessibility)
* [Checkbox](#checkbox)
* [Switch](#switch)
- [Rendering Anchor or Button](#rendering-anchor-or-button)
* [Example Components](#example-components-1)
* [Component Structure](#component-structure-1)
- [Converting Scoped to Shadow](#converting-scoped-to-shadow)
- [RTL](#rtl)
## Button States
@@ -373,6 +371,7 @@ ion-ripple-effect {
#### Example Components
- [ion-checkbox](https://github.com/ionic-team/ionic/tree/master/core/src/components/checkbox)
- [ion-toggle](https://github.com/ionic-team/ionic/tree/master/core/src/components/toggle)
#### VoiceOver
@@ -433,13 +432,9 @@ const { label, labelId, labelText } = getAriaLabel(el, inputId);
where `el` and `inputId` are the following:
```tsx
export class Checkbox implements ComponentInterface {
private inputId = `ion-cb-${checkboxIds++}`;
private inputId = `ion-cb-${checkboxIds++}`;
@Element() el!: HTMLElement;
...
}
@Element() el!: HTMLElement;
```
This can then be added to the `Host` like the following:
@@ -453,7 +448,7 @@ This can then be added to the `Host` like the following:
>
```
In addition to that, the checkbox input should have a label added:
In addition to that, the checkbox should have a label added:
```tsx
<Host
@@ -494,137 +489,6 @@ currently on a checkbox inside of a checkbox
This is a compromise we have to make in order for it to work with the other screen readers & Safari.
### Switch
#### Example Components
- [ion-toggle](https://github.com/ionic-team/ionic/tree/master/core/src/components/toggle)
#### Voiceover
In order for VoiceOver to work properly with a switch component there must be a native `input` with `type="checkbox"` and `role="switch"`, and `aria-checked` and `role="switch"` **must** be on the host element. The `aria-hidden` attribute needs to be added if the switch is disabled, preventing iOS users from selecting it:
```tsx
render() {
const { checked, disabled } = this;
return (
<Host
aria-checked={`${checked}`}
aria-hidden={disabled ? 'true' : null}
role="switch"
>
<input
type="checkbox"
role="switch"
/>
...
</Host>
);
}
```
#### NVDA
It is required to have `aria-checked` on the native input for checked to read properly and `disabled` to prevent tabbing to the input:
```tsx
render() {
const { checked, disabled } = this;
return (
<Host
aria-checked={`${checked}`}
aria-hidden={disabled ? 'true' : null}
role="switch"
>
<input
type="checkbox"
role="switch"
aria-checked={`${checked}`}
disabled={disabled}
/>
...
</Host>
);
}
```
#### Labels
A helper function has been created to get the proper `aria-label` for the switch. This can be imported as `getAriaLabel` like the following:
```tsx
const { label, labelId, labelText } = getAriaLabel(el, inputId);
```
where `el` and `inputId` are the following:
```tsx
export class Toggle implements ComponentInterface {
private inputId = `ion-tg-${toggleIds++}`;
@Element() el!: HTMLElement;
...
}
```
This can then be added to the `Host` like the following:
```tsx
<Host
aria-labelledby={label ? labelId : null}
aria-checked={`${checked}`}
aria-hidden={disabled ? 'true' : null}
role="switch"
>
```
In addition to that, the checkbox input should have a label added:
```tsx
<Host
aria-labelledby={label ? labelId : null}
aria-checked={`${checked}`}
aria-hidden={disabled ? 'true' : null}
role="switch"
>
<label htmlFor={inputId}>
{labelText}
</label>
<input
type="checkbox"
role="switch"
aria-checked={`${checked}`}
disabled={disabled}
id={inputId}
/>
```
#### Hidden Input
A helper function to render a hidden input has been added, it can be added in the `render`:
```tsx
renderHiddenInput(true, el, name, (checked ? value : ''), disabled);
```
> This is required for the switch to work with forms.
#### Known Issues
When using VoiceOver on macOS or iOS, Chrome will announce the switch as a checked or unchecked `checkbox`:
```
You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
```
There is a WebKit bug open for this: https://bugs.webkit.org/show_bug.cgi?id=196354
## Rendering Anchor or Button
Certain components can render an `<a>` or a `<button>` depending on the presence of an `href` attribute.
@@ -704,39 +568,3 @@ There will be some CSS issues when converting to shadow. Below are some of the d
/* IN SHADOW*/
:host-context(ion-toolbar:not(.ion-color)):host(:not(.ion-color)) ::slotted(ion-segment-button) {
```
## RTL
When you need to support both LTR and RTL modes, try to avoid using values such as `left` and `right`. For certain CSS properties, you can use the appropriate mixin to have this handled for you automatically.
For example, if you wanted `transform-origin` to be RTL-aware, you would use the `transform-origin` mixin:
```css
@include transform-origin(start, center);
```
This would output `transform-origin: left center` in LTR mode and `transform-origin: right center` in RTL mode.
These mixins depend on the `:host-context` pseudo-class when used inside of shadow components, which is not supported in WebKit. As a result, these mixins will not work in Safari for macOS and iOS when applied to shadow components.
To work around this, you should set an RTL class on the host of your component and set your RTL styles by targeting that class:
```tsx
<Host
class={{
'my-cmp-rtl': document.dir === 'rtl'
})
>
...
</Host>
```
```css
:host {
transform-origin: left center;
}
:host(.my-cmp-rtl) {
transform-origin: right center;
}
```

59
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,59 @@
---
name: Bug Report
about: Create a report to help us improve
title: 'bug: '
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use the Ionic Forum: https://forum.ionicframework.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Bug Report
**Ionic version:**
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
[ ] **4.x**
[x] **5.x**
**Current behavior:**
<!-- Describe how the bug manifests. -->
**Expected behavior:**
<!-- Describe what the behavior would be without the bug. -->
**Steps to reproduce:**
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
**Related code:**
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
A sample application via GitHub
StackBlitz (https://stackblitz.com)
Ionic Angular StackBlitz: https://stackblitz.com/edit/ionic-v4-angular-tabs
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
-->
```
insert short code snippets here
```
**Other information:**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->
**Ionic info:**
<!-- (run `ionic info` from a terminal/cmd prompt and paste output below): -->
```
insert the output from ionic info here
```

View File

@@ -1,56 +0,0 @@
name: 🐛 Bug Report
description: Create a report to help us improve Ionic Framework
title: 'bug: '
body:
- type: checkboxes
attributes:
label: Prequisites
description: Please ensure you have completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
required: true
- label: I agree to follow the [Code of Conduct](https://ionicframework.com/code-of-conduct).
required: true
- label: I have searched for [existing issues](https://github.com/ionic-team/ionic-framework/issues) that already report this problem, without success.
required: true
- type: checkboxes
attributes:
label: Ionic Framework Version
description: Please select which versions of Ionic Framework this issue impacts. For Ionic Framework 1.x issues, please use https://github.com/ionic-team/ionic-v1. For Ionic Framework 2.x and 3.x issues, please use https://github.com/ionic-team/ionic-v3.
options:
- label: v4.x
- label: v5.x
- label: v6.x
- type: textarea
attributes:
label: Current Behavior
description: A clear description of what the bug is and how it manifests.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: Please explain the steps required to duplicate this issue.
validations:
required: true
- type: input
attributes:
label: Code Reproduction URL
description: Please reproduce this issue in a blank Ionic Framework starter application and provide a link to the repo. Try out our [Getting Started Wizard](https://ionicframework.com/start#basics) to quickly spin up an Ionic Framework starter app. This is the best way to ensure this issue is triaged quickly. Issues without a code reproduction may be closed if the Ionic Team cannot reproduce the issue you are reporting.
placeholder: https://github.com/...
- type: textarea
attributes:
label: Ionic Info
description: Please run `ionic info` from within your Ionic Framework project directory and paste the output below.
validations:
requred: true
- type: textarea
attributes:
label: Additional Information
description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc.

11
.github/ISSUE_TEMPLATE/cli.md vendored Normal file
View File

@@ -0,0 +1,11 @@
---
name: CLI
about: Suggest an improvement for the CLI
title: ''
labels: 'ionitron: cli'
assignees: ''
---
# CLI
Please do not submit bug reports or feature requests related to the Ionic CLI. Instead, please submit an issue to the [Ionic CLI Repository](https://github.com/ionic-team/ionic-cli/issues/new/choose).

View File

@@ -1,10 +0,0 @@
contact_links:
- name: 📚 Documentation
url: https://github.com/ionic-team/ionic-docs/issues/new/choose
about: This issue tracker is not for documentation issues. Please file documentation issues on the Ionic Docs repo.
- name: 💻 CLI
url: https://github.com/ionic-team/ionic-cli/issues/new/choose
about: This issue tracker is not for CLI issues. Please file CLI issues on the Ionic CLI repo.
- name: 🤔 Support Question
url: https://forum.ionicframework.com/
about: This issue tracker is not for support questions. Please post your question on the Ionic Forums.

11
.github/ISSUE_TEMPLATE/documentation.md vendored Normal file
View File

@@ -0,0 +1,11 @@
---
name: Documentation
about: Suggest an improvement for the documentation of this project
title: ''
labels: 'ionitron: docs'
assignees: ''
---
# Documentation
Please do not submit issues on how to improve or fix the documentation. Instead, please submit an issue to the [Ionic Docs Repository](https://github.com/ionic-team/ionic-docs/issues/new/choose).

View File

@@ -0,0 +1,37 @@
---
name: Feature Request
about: Suggest an idea for this project
title: 'feat: '
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Feature Request
**Ionic version:**
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
[x] **4.x**
**Describe the Feature Request**
<!-- A clear and concise description of what the feature request is. Please include if your feature request is related to a problem. -->
**Describe Preferred Solution**
<!-- A clear and concise description of what you want to happen. -->
**Describe Alternatives**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Related Code**
<!-- If you are able to illustrate the feature request with an example, please provide a sample application via an online code collaborator such as [StackBlitz](https://stackblitz.com), or [GitHub](https://github.com). -->
**Additional Context**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to add, use case, Stack Overflow links, forum links, screenshots, OS if applicable, etc. -->

View File

@@ -1,43 +0,0 @@
name: 💡 Feature Request
description: Suggest an idea for Ionic Framework
title: 'feat: '
body:
- type: checkboxes
attributes:
label: Prequisites
description: Please ensure you have completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
required: true
- label: I agree to follow the [Code of Conduct](https://ionicframework.com/code-of-conduct).
required: true
- label: I have searched for [existing issues](https://github.com/ionic-team/ionic-framework/issues) that already include this feature request, without success.
required: true
- type: textarea
attributes:
label: Describe the Feature Request
description: A clear and concise description of what the feature does.
validations:
required: true
- type: textarea
attributes:
label: Describe the Use Case
description: A clear and concise use case for what problem this feature would solve.
validations:
required: true
- type: textarea
attributes:
label: Describe Preferred Solution
description: A clear and concise description of what you how you want this feature to be added to Ionic Framework.
- type: textarea
attributes:
label: Describe Alternatives
description: A clear and concise description of any alternative solutions or features you have considered.
- type: textarea
attributes:
label: Related Code
description: If you are able to illustrate the feature request with an example, please provide a sample Ionic Framework application. Try out our [Getting Started Wizard](https://ionicframework.com/start#basics) to quickly spin up an Ionic Framework starter app.
- type: textarea
attributes:
label: Additional Information
description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to implement, Stack Overflow links, forum links, etc.

View File

@@ -0,0 +1,11 @@
---
name: Support Question
about: Question on how to use this project
title: 'support: '
labels: 'ionitron: support'
assignees: ''
---
# Support Question
Please do not submit support requests or "How to" questions here. Instead, please use the Ionic Forum: https://forum.ionicframework.com/

12
.github/PROCESS.md vendored
View File

@@ -77,15 +77,7 @@ NOTE: be sure to perform those actions in the order stated. If you add the comme
If there is a response to the question, the bot will remove the `needs: reply` and apply the `triage` label. The issue will then go through the triage handling again.
If there is no response within 14 days, the issue will be closed and locked.
### Missing Code Reproduction
If the information the submitter has supplied is not enough for you to reproduce the issue, add the `ionitron: needs reproduction` label. An automated comment will be added to the thread asking the submitter to provide a code reproduction of the issue.
This label can also be added when the submitter has supplied some code, but not enough for you to reproduce the issue (i.e. code snippets).
Issues with this label are not automatically closed and locked, so we manually close and lock them if there is no response within 14 days.
If there is no response within 30 days, the issue will be closed and locked.
## Workflow
@@ -150,7 +142,7 @@ See the [steps for releasing](#releasing) below for detailed information on how
### Version Branches
Once a release has shipped and the release branch has been merged into `stable` and `master` it should also be merged into its corresponding version branch. These version branches allow us to ship updates for specific versions of the framework (i.e. Lets us ship a bug fix that only affects 4.2.x).
Once a release has shipped and the release branch has been merged into `stable` and `master` it should also be merged into its corrsponding version branch. These version branches allow us to ship updates for specific versions of the framework (i.e. Lets us ship a bug fix that only affects 4.2.x).
Patch releases should be merged into their corresponding version branches. For example, a `release-4.1.1` branch should be merged into the `4.1.x` version branch and a `release-5.0.1` branch should be merged into the `5.0.x` version branch.

2
.gitignore vendored
View File

@@ -59,10 +59,10 @@ prerender-static.html
angular/css/
packages/react/css/
packages/vue/css/
core/components/
core/css/
core/hydrate/
core/loader/
core/www/
.stencil/
angular/build/
core/components/

View File

@@ -7,25 +7,7 @@ const fs = require('fs');
[
// core
{
files: [
'../core/css/core.css',
'../core/css/core.css.map',
'../core/css/normalize.css',
'../core/css/normalize.css.map',
'../core/components/index.js',
'../core/components/index.d.ts',
'../core/components/package.json',
'../core/dist/index.js',
'../core/dist/ionic/index.esm.js',
]
},
// hydrate
{
files: [
'../core/hydrate/index.js',
'../core/hydrate/index.d.ts',
'../core/hydrate/package.json'
]
files: ['../core/dist/index.js', '../core/dist/ionic/index.esm.js']
},
// angular
{

View File

@@ -1,233 +1,3 @@
# [5.7.0 Potassium](https://github.com/ionic-team/ionic/compare/v5.6.14...v5.7.0) (2021-09-01)
### Bug Fixes
* **alert:** AlertButton role now has correct types ([#23791](https://github.com/ionic-team/ionic/issues/23791)) ([864212b](https://github.com/ionic-team/ionic/commit/864212b0f28d33daede5f4767aa03efa37c219ae))
* **label:** label now only takes up as much space as needed when slotted ([#23807](https://github.com/ionic-team/ionic/issues/23807)) ([9932e26](https://github.com/ionic-team/ionic/commit/9932e26a2ef28317bc85761e71a8fc4d881b8ae8)), closes [#23806](https://github.com/ionic-team/ionic/issues/23806)
* **reorder-group:** dragging reorder item to bottom no longer gives out of bounds index ([#23797](https://github.com/ionic-team/ionic/issues/23797)) ([02409f2](https://github.com/ionic-team/ionic/commit/02409f2abfa8acbab05d0f1217b9d1c13721746e)), closes [#23796](https://github.com/ionic-team/ionic/issues/23796)
* **vue:** router guards are now fire correctly when written in a component ([#23821](https://github.com/ionic-team/ionic/issues/23821)) ([3c44222](https://github.com/ionic-team/ionic/commit/3c442228ff746165fd823687a2661a24edd08820)), closes [#23820](https://github.com/ionic-team/ionic/issues/23820)
### Features
* **slides:** add IonicSlides module for Swiper migration, deprecate ion-slides ([#23844](https://github.com/ionic-team/ionic/issues/23844)) ([11fda41](https://github.com/ionic-team/ionic/commit/11fda41420343886dabd97096690be38f1c40524)), closes [#23447](https://github.com/ionic-team/ionic/issues/23447)
### Code Refactoring
* **virtual-scroll:** deprecated virtual scroll in favor of solutions provided by JS frameworks ([#23854](https://github.com/ionic-team/ionic-framework/pull/23854)) ([a0229bc](https://github.com/ionic-team/ionic-framework/commit/a0229bc7b2edb061510de0f2042e7910d04accc0))
## [5.6.14](https://github.com/ionic-team/ionic/compare/v5.6.13...v5.6.14) (2021-08-18)
### Bug Fixes
* **back-button:** MD ripple now accounts for --ripple-color ([#23749](https://github.com/ionic-team/ionic/issues/23749)) ([6b18a89](https://github.com/ionic-team/ionic/commit/6b18a89ac2c446082ce7faebe329157eedb13a0e)), closes [#23748](https://github.com/ionic-team/ionic/issues/23748)
* **img:** correctly determine when to load image when scrolling quickly on slower devices ([#23704](https://github.com/ionic-team/ionic/issues/23704)) ([067e621](https://github.com/ionic-team/ionic/commit/067e621bbc3865184ae114b8c91122188c13c860)), closes [#23703](https://github.com/ionic-team/ionic/issues/23703)
* **item-sliding:** prevent scrolling during slide gesture ([#23774](https://github.com/ionic-team/ionic/issues/23774)) ([e0c4ad3](https://github.com/ionic-team/ionic/commit/e0c4ad30bec3f2bd325d65b210ffb0437149810f)), closes [#19564](https://github.com/ionic-team/ionic/issues/19564)
* **nav:** custom animation is now used correctly ([#23779](https://github.com/ionic-team/ionic/issues/23779)) ([f9415ef](https://github.com/ionic-team/ionic/commit/f9415ef8a689e26078bdd01623348c79f9f818ad)), closes [#23777](https://github.com/ionic-team/ionic/issues/23777)
* **vue:** using router.go now shows correct view ([#23773](https://github.com/ionic-team/ionic/issues/23773)) ([621f4fa](https://github.com/ionic-team/ionic/commit/621f4faa1ab03137158127a56c7fe0aa1f7ae489)), closes [#22563](https://github.com/ionic-team/ionic/issues/22563)
## [5.6.13](https://github.com/ionic-team/ionic/compare/v5.6.12...v5.6.13) (2021-08-04)
### Bug Fixes
* **checkbox, radio:** change event interfaces correctly use TypeScript generics for value ([#23044](https://github.com/ionic-team/ionic/issues/23044)) ([8a941fd](https://github.com/ionic-team/ionic/commit/8a941fd24cd138817a2e91c42898878a919538e4))
* **gesture:** onEnd now correctly fires even if the event target was removed from the DOM ([#23713](https://github.com/ionic-team/ionic/issues/23713)) ([4edb5e2](https://github.com/ionic-team/ionic/commit/4edb5e2fed55c8ea21eae50821d16d351bf3aebf)), closes [#22819](https://github.com/ionic-team/ionic/issues/22819)
* **item-sliding:** opening item while other items are open no longer requires multiple swipes ([#23683](https://github.com/ionic-team/ionic/issues/23683)) ([792864f](https://github.com/ionic-team/ionic/commit/792864f8ab21dc178c1836a8a0d4fe2d305cc142)), closes [#21579](https://github.com/ionic-team/ionic/issues/21579)
* **react:** IonTabs no longer causes SSR to fail ([#23696](https://github.com/ionic-team/ionic/issues/23696)) ([f2a05be](https://github.com/ionic-team/ionic/commit/f2a05bed1e2a1150e8f1823bfed2d12a219d6ad0)), closes [#23651](https://github.com/ionic-team/ionic/issues/23651)
* **vue:** improve accuracy of ion-page dev warning ([#23677](https://github.com/ionic-team/ionic/issues/23677)) ([fb260a9](https://github.com/ionic-team/ionic/commit/fb260a9e09e6f3912b30ef2ebf581d3216483fea)), closes [#23675](https://github.com/ionic-team/ionic/issues/23675)
* **vue:** tabs warning about user-provided router outlet change is now correctly logged ([#23724](https://github.com/ionic-team/ionic/issues/23724)) ([4a64e97](https://github.com/ionic-team/ionic/commit/4a64e97a3e390e365101bbb477acad0ddc4671ff)), closes [#23719](https://github.com/ionic-team/ionic/issues/23719)
## [5.6.12](https://github.com/ionic-team/ionic/compare/v5.6.11...v5.6.12) (2021-07-21)
### Bug Fixes
* **action-sheet:** header, subheader, and icon alignment better matches native ios ([#23322](https://github.com/ionic-team/ionic/issues/23322)) ([39315bc](https://github.com/ionic-team/ionic/commit/39315bc857b850347dca386776665e21c9742cad)), closes [#23317](https://github.com/ionic-team/ionic/issues/23317)
* **button:** buttons are now disabled during page transitions ([#23589](https://github.com/ionic-team/ionic/issues/23589)) ([3b803eb](https://github.com/ionic-team/ionic/commit/3b803ebe024be3dbcf814a30a18df51ce23c8880)), closes [#23588](https://github.com/ionic-team/ionic/issues/23588)
* **item:** mirror disabled prop to aria attribute ([#23544](https://github.com/ionic-team/ionic/issues/23544)) ([9021e7c](https://github.com/ionic-team/ionic/commit/9021e7cc4b48a69ccc94faa7d2ddcb10a2afa340)), closes [#23513](https://github.com/ionic-team/ionic/issues/23513)
* **menu-button:** custom aria-label can now be set ([#23608](https://github.com/ionic-team/ionic/issues/23608)) ([c08345d](https://github.com/ionic-team/ionic/commit/c08345df2ee3175f3f0d11ff877c7b6f1a102321)), closes [#23604](https://github.com/ionic-team/ionic/issues/23604)
* **overlays:** overlay interfaces are now exported from framework packages and documented ([#23619](https://github.com/ionic-team/ionic/issues/23619)) ([773bbcb](https://github.com/ionic-team/ionic/commit/773bbcb211d3cf0caf38c25b44e666d98ddfafe5)), closes [#22790](https://github.com/ionic-team/ionic/issues/22790)
* **router-outlet:** improve reliability of swipe back gesture when quickly swiping back ([#23527](https://github.com/ionic-team/ionic/issues/23527)) ([fa06942](https://github.com/ionic-team/ionic/commit/fa069424b265891852a07869b6d086a1cb041e93)), closes [#22895](https://github.com/ionic-team/ionic/issues/22895)
## [5.6.11](https://github.com/ionic-team/ionic/compare/v5.6.10...v5.6.11) (2021-07-01)
### Bug Fixes
* **animation:** typescript interface has correct return value for progress methods ([#23536](https://github.com/ionic-team/ionic/issues/23536)) ([f3d6abb](https://github.com/ionic-team/ionic/commit/f3d6abbc1beeafe3b5e7f473d70d0b8ef4c79bc8))
* **ios, md:** double tapping back button no longer causes app to go back 2 pages ([#23526](https://github.com/ionic-team/ionic/issues/23526)) ([69be51d](https://github.com/ionic-team/ionic/commit/69be51dc54e670b2f75cbfac28a4a09517dbf355)), closes [#18455](https://github.com/ionic-team/ionic/issues/18455)
## [5.6.10](https://github.com/ionic-team/ionic/compare/v5.6.9...v5.6.10) (2021-06-22)
### Bug Fixes
* **button:** buttons using fill and color properties now account for hover and focused opacity variables ([#23442](https://github.com/ionic-team/ionic/issues/23442)) ([68c0e71](https://github.com/ionic-team/ionic/commit/68c0e7136d3f8aad8a195a0371104f7dd5fa7060)), closes [#23441](https://github.com/ionic-team/ionic/issues/23441)
* **item:** using multiple items with inputs no longer results in console warnings ([#23429](https://github.com/ionic-team/ionic/issues/23429)) ([e27b5b6](https://github.com/ionic-team/ionic/commit/e27b5b6ae360c44d8521ac7191817cbbe0367c05)), closes [#23427](https://github.com/ionic-team/ionic/issues/23427)
* **vue:** IonTabs can now accept IonRouterOutlet, deprecated default router outlet in tabs ([#23477](https://github.com/ionic-team/ionic/issues/23477)) ([a2a4cff](https://github.com/ionic-team/ionic/commit/a2a4cff3d0d67868f384e1e9eec7cc738e260a27)), closes [#23321](https://github.com/ionic-team/ionic/issues/23321)
## [5.6.9](https://github.com/ionic-team/ionic/compare/v5.6.8...v5.6.9) (2021-06-08)
### Bug Fixes
* **modal:** swipe to close modal is no longer swipeable on footer ([#23401](https://github.com/ionic-team/ionic/issues/23401)) ([ae96563](https://github.com/ionic-team/ionic/commit/ae96563fb3c4612cb8585292b389ee746f5759f7)), closes [#23398](https://github.com/ionic-team/ionic/issues/23398)
* **title:** inherit padding for iOS title in a toolbar ([#23343](https://github.com/ionic-team/ionic/issues/23343)) ([82cfa55](https://github.com/ionic-team/ionic/commit/82cfa5565347704b0e9f7dac792ed2aa6dd30505)), closes [#23072](https://github.com/ionic-team/ionic/issues/23072)
* **vue:** improve v-model integration for Vue 3.1.0+ ([#23420](https://github.com/ionic-team/ionic/issues/23420)) ([f008628](https://github.com/ionic-team/ionic/commit/f0086288512bd7f7d1929d79bfd8bf702efc732e))
* **vue:** prevent error from being thrown when testing on certain jest runners ([#23421](https://github.com/ionic-team/ionic/issues/23421)) ([60bedb5](https://github.com/ionic-team/ionic/commit/60bedb5599b286bffccfc54c4861a269d9b8df73)), closes [#23397](https://github.com/ionic-team/ionic/issues/23397)
## [5.6.8](https://github.com/ionic-team/ionic/compare/v5.6.7...v5.6.8) (2021-05-27)
### Bug Fixes
* **action-sheet:** subheader no longer overlaps action sheet buttons ([#23318](https://github.com/ionic-team/ionic/issues/23318)) ([d473a53](https://github.com/ionic-team/ionic/commit/d473a5385108ef5f39d7c9a2b2924e89fec631de)), closes [#23316](https://github.com/ionic-team/ionic/issues/23316)
* **all:** reflect color property as an attribute for vue ([#23345](https://github.com/ionic-team/ionic/issues/23345)) ([dc430af](https://github.com/ionic-team/ionic/commit/dc430af906c608f948c8d404ad73ae0e0ac36076)), closes [#23323](https://github.com/ionic-team/ionic/issues/23323)
* **range:** knob can now have an accessible name ([#23338](https://github.com/ionic-team/ionic/issues/23338)) ([881dcff](https://github.com/ionic-team/ionic/commit/881dcff40b8bdcb07b27d4ee812ce4ee64b6ea9a)), closes [#23295](https://github.com/ionic-team/ionic/issues/23295)
* **react:** remove @ionic/core dependency in @ionic/react-router to resolve yarn install warning ([#23351](https://github.com/ionic-team/ionic/issues/23351)) ([36bfa33](https://github.com/ionic-team/ionic/commit/36bfa3350354e09be6c62f4e4bee0c553c5981a3)), closes [#23346](https://github.com/ionic-team/ionic/issues/23346)
* **react:** support history@5 in preparation for react router 6 ([#23297](https://github.com/ionic-team/ionic/issues/23297)) ([4da5216](https://github.com/ionic-team/ionic/commit/4da5216b4f65f3d893cc81ebee77261835218f7f)), closes [#23294](https://github.com/ionic-team/ionic/issues/23294)
* **router:** guards are now triggered on initial navigation ([#23123](https://github.com/ionic-team/ionic/issues/23123)) ([56f6f56](https://github.com/ionic-team/ionic/commit/56f6f56c6665f40ea6bf41be463cd416883359f7)), closes [#22936](https://github.com/ionic-team/ionic/issues/22936)
* **router:** redirects now account for query string ([#23337](https://github.com/ionic-team/ionic/issues/23337)) ([08a9f3a](https://github.com/ionic-team/ionic/commit/08a9f3ac94685c5782dd2fa6b56bf3448729a768)), closes [#23136](https://github.com/ionic-team/ionic/issues/23136)
* **skeleton-text:** animation no longer jumps on large skeleton text elements ([#22697](https://github.com/ionic-team/ionic/issues/22697)) ([1a36922](https://github.com/ionic-team/ionic/commit/1a36922f41f2890c778feedbad9c5b74a72a3907)), closes [#22694](https://github.com/ionic-team/ionic/issues/22694)
* **slides:** resolve prototype pollution in swiper v5 ([#23344](https://github.com/ionic-team/ionic/issues/23344)) ([a708c41](https://github.com/ionic-team/ionic/commit/a708c412625cba475ec7863468dcc2146b8feb7a)), closes [#23342](https://github.com/ionic-team/ionic/issues/23342)
* **title:** large title scale animation is now correct in rtl mode ([#23372](https://github.com/ionic-team/ionic/issues/23372)) ([3d474ec](https://github.com/ionic-team/ionic/commit/3d474ec67ff4192fa3d08e370e20fecbee99a6aa)), closes [#23371](https://github.com/ionic-team/ionic/issues/23371)
## [5.6.7](https://github.com/ionic-team/ionic/compare/v5.6.6...v5.6.7) (2021-05-13)
### Bug Fixes
* **angular:** warnings are no longer generated when running tests with ng test ([#23292](https://github.com/ionic-team/ionic/issues/23292)) ([9cb6c80](https://github.com/ionic-team/ionic/commit/9cb6c80b3db4273e9c003a62a3065427995cb353)), closes [#19926](https://github.com/ionic-team/ionic/issues/19926)
* **overlays:** screen readers no longer read content behind overlays ([#23284](https://github.com/ionic-team/ionic/issues/23284)) ([a9b12a5](https://github.com/ionic-team/ionic/commit/a9b12a5aa4c150a1f8a80a826dda0df350bc0092)), closes [#22714](https://github.com/ionic-team/ionic/issues/22714)
* **refresher:** refresher now only activates when pulling down on MD ([#23283](https://github.com/ionic-team/ionic/issues/23283)) ([1e1596f](https://github.com/ionic-team/ionic/commit/1e1596f471e440085bf2d90e473f0cb0c0dcf6e2)), closes [#23245](https://github.com/ionic-team/ionic/issues/23245)
* **vue:** use correct history mode when doing ssr to avoid errors ([#23255](https://github.com/ionic-team/ionic/issues/23255)) ([2e00dab](https://github.com/ionic-team/ionic/commit/2e00dab95d3fefeab92c19cedb046ae2bb10879c)), closes [#23254](https://github.com/ionic-team/ionic/issues/23254)
## [5.6.6](https://github.com/ionic-team/ionic/compare/v5.6.5...v5.6.6) (2021-04-29)
### Bug Fixes
* **angular:** back button goes back to proper tab on angular 11.2.10 ([#23238](https://github.com/ionic-team/ionic/issues/23238)) ([e436439](https://github.com/ionic-team/ionic/commit/e436439e10c895b203ca4dc889cf307ffb9524b4)), closes [#23230](https://github.com/ionic-team/ionic/issues/23230)
* **react:** remove hardware back button event listener when NavManager is unmounted ([#23224](https://github.com/ionic-team/ionic/issues/23224)) ([c501da7](https://github.com/ionic-team/ionic/commit/c501da73be879db0fea818c507bae4386a47d42e)), closes [#23170](https://github.com/ionic-team/ionic/issues/23170)
* **slides:** undefined error is no longer thrown after destroying and quickly re-creating ion-slides ([#23239](https://github.com/ionic-team/ionic/issues/23239)) ([2ccaabb](https://github.com/ionic-team/ionic/commit/2ccaabb5b4d67ec4b1318e3ccb3edc1bd853ab3e)), closes [#22289](https://github.com/ionic-team/ionic/issues/22289)
* **vue:** components inside of ion-nav are now unmounted properly ([#23240](https://github.com/ionic-team/ionic/issues/23240)) ([f2f41e2](https://github.com/ionic-team/ionic/commit/f2f41e2af45ba9a36064d33e0b5c1b59da6b74ab)), closes [#23233](https://github.com/ionic-team/ionic/issues/23233)
* **vue:** overlay events can now be listened for without the "on" prefix, deprecated "on" prefix event listeners ([#23227](https://github.com/ionic-team/ionic/issues/23227)) ([dab927d](https://github.com/ionic-team/ionic/commit/dab927d2901658f4040c1d1aa6c777497d8714c8))
## [5.6.5](https://github.com/ionic-team/ionic/compare/v5.6.4...v5.6.5) (2021-04-22)
### Bug Fixes
* **content:** only render a main element when content is being used in primary view ([#23160](https://github.com/ionic-team/ionic/issues/23160)) ([2d07d82](https://github.com/ionic-team/ionic/commit/2d07d8216af908b181c5e7e438e79a049bb6d8c2))
* **datetime, input, textarea:** only add aria-labelledby if there is an adjacent label ([#23211](https://github.com/ionic-team/ionic/issues/23211)) ([a31fb55](https://github.com/ionic-team/ionic/commit/a31fb55bac1ef03e014f3d7f6c22c24eff20feb5))
* **radio-group:** pressing spacebar correctly unselects radio with allow-empty-selection ([#23194](https://github.com/ionic-team/ionic/issues/23194)) ([7139b3f](https://github.com/ionic-team/ionic/commit/7139b3f39e8eeef07ff7c595940fc5dafe062956)), closes [#22734](https://github.com/ionic-team/ionic/issues/22734)
* **react:** callback refs now work correctly with ionic components ([#23152](https://github.com/ionic-team/ionic/issues/23152)) ([0dd189e](https://github.com/ionic-team/ionic/commit/0dd189e2c05012659894a4c15cd3a9d407fe0a63)), closes [#23153](https://github.com/ionic-team/ionic/issues/23153)
* **segment, segment-button:** use tablist and tab roles ([#23145](https://github.com/ionic-team/ionic/issues/23145)) ([91ac340](https://github.com/ionic-team/ionic/commit/91ac340ae7e8928f7b0972a093dd9dd7fa727671))
* **vue:** dynamic tabs are now correctly recognized ([#23212](https://github.com/ionic-team/ionic/issues/23212)) ([004885b](https://github.com/ionic-team/ionic/commit/004885bfd4446487e6386876c868532a2795347f)), closes [#22847](https://github.com/ionic-team/ionic/issues/22847)
* **vue:** update props when navigating to new parameterized route ([#23189](https://github.com/ionic-team/ionic/issues/23189)) ([35c8802](https://github.com/ionic-team/ionic/commit/35c8802c22c1f4bf213a01e1c28398ad62d1b7ac))
## [5.6.4](https://github.com/ionic-team/ionic/compare/v5.6.3...v5.6.4) (2021-04-08)
### Bug Fixes
* **angular:** swiping back quickly no longer causes app to get stuck ([#23125](https://github.com/ionic-team/ionic/issues/23125)) ([28c52fd](https://github.com/ionic-team/ionic/commit/28c52fd4e3df3d96b4ec83075a322e110e938a1a)), closes [#15154](https://github.com/ionic-team/ionic/issues/15154)
* **input:** inherit aria-label to input ([#23159](https://github.com/ionic-team/ionic/issues/23159)) ([61f094d](https://github.com/ionic-team/ionic/commit/61f094d30665c9afec428028883a5d9a085892d8))
* **react:** overlays now correctly unmount any child components after dismissing ([#23149](https://github.com/ionic-team/ionic/issues/23149)) ([dee6eb3](https://github.com/ionic-team/ionic/commit/dee6eb30df370047bbc872b00ab6d801dd11fa81)), closes [#23140](https://github.com/ionic-team/ionic/issues/23140)
* **react, vue:** correct view now chosen when going back inside tabs ([#23154](https://github.com/ionic-team/ionic/issues/23154)) ([7203190](https://github.com/ionic-team/ionic/commit/72031902347dc279045e2e099f69852a23dd8436)), closes [#23087](https://github.com/ionic-team/ionic/issues/23087) [#23101](https://github.com/ionic-team/ionic/issues/23101)
* **toggle:** prevent click event from firing twice ([#23146](https://github.com/ionic-team/ionic/issues/23146)) ([42e6c90](https://github.com/ionic-team/ionic/commit/42e6c90c4632423386b165dddc4b94a55c075e2e)), closes [#23041](https://github.com/ionic-team/ionic/issues/23041)
* **vue:** account for event name changes in vue 3.0.6+ for overlay components ([#23100](https://github.com/ionic-team/ionic/issues/23100)) ([27318cf](https://github.com/ionic-team/ionic/commit/27318cf58563c4b38d0b7045fb61451f45954a8f))
* **vue:** components now integrate properly with vee-validate ([#23114](https://github.com/ionic-team/ionic/issues/23114)) ([ba51daf](https://github.com/ionic-team/ionic/commit/ba51daf17c4438aea6826882f82a04ebf8d6a5d8)), closes [#22886](https://github.com/ionic-team/ionic/issues/22886)
## [5.6.3](https://github.com/ionic-team/ionic/compare/v5.6.2...v5.6.3) (2021-03-23)
### Bug Fixes
* **all:** update tslib to resolve export errors ([#23092](https://github.com/ionic-team/ionic-framework/pull/23092)) ([0cdd326](https://github.com/ionic-team/ionic-framework/commit/0cdd326a4a02729a306bccfcadca7370475eae32)), closes [#23090](https://github.com/ionic-team/ionic-framework/issues/23090)
* **react:** correctly show ion-back-button when going back ([#23069](https://github.com/ionic-team/ionic/issues/23069)) ([1c93b75](https://github.com/ionic-team/ionic/commit/1c93b75e397961e374620eb43bee3d6bb4389836)), closes [#22692](https://github.com/ionic-team/ionic/issues/22692)
## [5.6.2](https://github.com/ionic-team/ionic/compare/v5.6.1...v5.6.2) (2021-03-22)
### Bug Fixes
* **item:** detail icon now respects rtl mode ([#23081](https://github.com/ionic-team/ionic/issues/23081)) ([b04fb6e](https://github.com/ionic-team/ionic/commit/b04fb6e849bc9d6283271aaadc2b8aaae1f3961d)), closes [#23078](https://github.com/ionic-team/ionic/issues/23078)
## [5.6.1](https://github.com/ionic-team/ionic/compare/v5.6.0...v5.6.1) (2021-03-17)
### Bug Fixes
* **custom-elements:** overlays now present correctly when using custom elements build ([#23039](https://github.com/ionic-team/ionic/issues/23039)) ([e4bf052](https://github.com/ionic-team/ionic/commit/e4bf052794af9aac07f887013b9250d2a045eba3)), closes [#23029](https://github.com/ionic-team/ionic/issues/23029)
* **item:** detail icon is no longer announced by screen readers ([#23055](https://github.com/ionic-team/ionic/issues/23055)) ([c877061](https://github.com/ionic-team/ionic/commit/c877061a328c6ab6fa7248b9880d0205c6c4f6c1)), closes [#23054](https://github.com/ionic-team/ionic/issues/23054)
* **label:** properly float labels for non-input items ([#23060](https://github.com/ionic-team/ionic/issues/23060)) ([c8a3999](https://github.com/ionic-team/ionic/commit/c8a3999da109b1719777f2acb791ab5388d371ea))
* **react:** only pass tab event props from IonTabs to IonTabBar if defined ([#23024](https://github.com/ionic-team/ionic/issues/23024)) ([f94e618](https://github.com/ionic-team/ionic/commit/f94e618a7b307b143eb39c061dc9e6b80e11f862)), closes [#23023](https://github.com/ionic-team/ionic/issues/23023)
* **refresher:** progressEnd no longer errors when pulling quickly in MD native refresher ([#23056](https://github.com/ionic-team/ionic/issues/23056)) ([67617fb](https://github.com/ionic-team/ionic/commit/67617fbc0f7ec825f1fa4c6e7e2da70e3fcd2d66))
* **virtual-scroll:** allow null in items property ([#23047](https://github.com/ionic-team/ionic/issues/23047)) ([2a253a1](https://github.com/ionic-team/ionic/commit/2a253a1d334ca2c6a478a5bc426e3115268a29af))
* **vue:** passing params as props are correctly updated when switching pages ([#23049](https://github.com/ionic-team/ionic/issues/23049)) ([2f54bc1](https://github.com/ionic-team/ionic/commit/2f54bc14699656e6905452a4233d982f83d0001f)), closes [#23043](https://github.com/ionic-team/ionic/issues/23043)
# [5.6.0 Argon](https://github.com/ionic-team/ionic/compare/v5.5.4...v5.6.0) (2021-03-04)
### Bug Fixes
* **all:** improve support for ids with special characters when getting label element ([#22680](https://github.com/ionic-team/ionic/issues/22680)) ([19d63f6](https://github.com/ionic-team/ionic/commit/19d63f62431ef9d8279f1726dd63fac2f0d4b46b)), closes [#22678](https://github.com/ionic-team/ionic/issues/22678)
* **header:** collapsed toolbar is no longer incorrectly shown when using ion-refresher ([#22937](https://github.com/ionic-team/ionic/issues/22937)) ([5300dcc](https://github.com/ionic-team/ionic/commit/5300dcc693caf51a726f8c346cfc9a44474fd3d1)), closes [#22829](https://github.com/ionic-team/ionic/issues/22829)
* **label:** only show placeholder with floating label when focused ([#22958](https://github.com/ionic-team/ionic/issues/22958)) ([9282aa6](https://github.com/ionic-team/ionic/commit/9282aa68715c088e9c8fcd915e78fb7ae91f551f)), closes [#17571](https://github.com/ionic-team/ionic/issues/17571)
* **progress-bar:** use correct theme colors in dark mode ([#22965](https://github.com/ionic-team/ionic/issues/22965)) ([b6b2714](https://github.com/ionic-team/ionic/commit/b6b2714d70f71255315510c5e49708944875db72)), closes [#20098](https://github.com/ionic-team/ionic/issues/20098)
* **radio-group:** pressing space no longer jumps screen to bottom of page ([#22892](https://github.com/ionic-team/ionic/issues/22892)) ([3a0465e](https://github.com/ionic-team/ionic/commit/3a0465e7d6f9e3cb01336a8bdbd7001e4ec34559)), closes [#22716](https://github.com/ionic-team/ionic/issues/22716)
* **react:** IonRouterOutlet now respects animated={false} prop ([#22905](https://github.com/ionic-team/ionic/issues/22905)) ([da1b7a0](https://github.com/ionic-team/ionic/commit/da1b7a0e7a9a5e6a9120dc4d5459c97d8bca5390)), closes [#22903](https://github.com/ionic-team/ionic/issues/22903)
* **react:** onIonTabsWillChange and onIonTabsDidChange event handlers are now properly bound to IonTabs ([#22233](https://github.com/ionic-team/ionic/issues/22233)) ([b064fde](https://github.com/ionic-team/ionic/commit/b064fdebef14018b77242b791914d5bb10863d39))
* **react, vue:** navigating using ion-back-button now selects correct page ([#22974](https://github.com/ionic-team/ionic/issues/22974)) ([cd8ffd8](https://github.com/ionic-team/ionic/commit/cd8ffd82a03ee69ef4cbd7922544bfc39680def9)), closes [#22830](https://github.com/ionic-team/ionic/issues/22830)
* **react, vue:** tab buttons no longer throw an error if href is undefined ([#22998](https://github.com/ionic-team/ionic/issues/22998)) ([943e3f6](https://github.com/ionic-team/ionic/commit/943e3f6ae37ecc56f21168f057dde77a05e4e144)), closes [#22997](https://github.com/ionic-team/ionic/issues/22997)
* **refresher:** add correct dark mode styles ([#22639](https://github.com/ionic-team/ionic/issues/22639)) ([c05476b](https://github.com/ionic-team/ionic/commit/c05476b88e3e6884b4c490461c9c67dee3dca83d)), closes [#22637](https://github.com/ionic-team/ionic/issues/22637)
* **vue:** correctly remove active state from tab button when navigating away from tab ([#23000](https://github.com/ionic-team/ionic/issues/23000)) ([a2763af](https://github.com/ionic-team/ionic/commit/a2763afe8e1fe1dc0decdbcb757a03bc5038045e)), closes [#22597](https://github.com/ionic-team/ionic/issues/22597)
* **vue:** prevent race conditions when opening overlays ([#22883](https://github.com/ionic-team/ionic/issues/22883)) ([68a9b80](https://github.com/ionic-team/ionic/commit/68a9b800532f9c0b308a3b74ed18a7068a942301)), closes [#22880](https://github.com/ionic-team/ionic/issues/22880)
### Features
* **custom-elements:** add experimental custom elements build ([#22863](https://github.com/ionic-team/ionic/issues/22863)) ([0de75af](https://github.com/ionic-team/ionic/commit/0de75afbefc521c1d76adcd587f77ba19c285a95))
* **progress-bar:** add parts for more design customization ([#22938](https://github.com/ionic-team/ionic/issues/22938)) ([e256d3f](https://github.com/ionic-team/ionic/commit/e256d3f09fd6f231c4d9e1d0f0927612a591466b)), closes [#20062](https://github.com/ionic-team/ionic/issues/20062) [#21820](https://github.com/ionic-team/ionic/issues/21820)
* **react:** add react hooks to control overlay components ([#22484](https://github.com/ionic-team/ionic/issues/22484)) ([b83e009](https://github.com/ionic-team/ionic/commit/b83e00934e794a936c9d3d23d7f94bbe89cedcd5))
* **searchbar:** add showClearIcon property ([#22759](https://github.com/ionic-team/ionic/issues/22759)) ([215eb5d](https://github.com/ionic-team/ionic/commit/215eb5d4efbb9ade942dba1687469caf61da21e7)), closes [#22738](https://github.com/ionic-team/ionic/issues/22738)
* **vue:** add composition API ionic lifecycle hooks ([#22970](https://github.com/ionic-team/ionic/issues/22970)) ([dd1c8db](https://github.com/ionic-team/ionic/commit/dd1c8dbf3b20fbd423f70c96846d9c366d90e7c5)), closes [#22769](https://github.com/ionic-team/ionic/issues/22769)
## [5.5.5](https://github.com/ionic-team/ionic/compare/v5.5.4...v5.5.5) (2021-02-26)

View File

@@ -16,14 +16,14 @@ diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include the ability to:
community include:
* 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
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:

View File

@@ -5,9 +5,6 @@ build top quality native and progressive web apps with web technologies.
Ionic Framework is based on [Web Components](https://www.webcomponents.org/introduction) and comes with many significant performance, usability, and feature improvements over the past versions.
## Looking for the Ionic Framework v6 beta?
[Click here to get started!](https://github.com/ionic-team/ionic-framework/blob/next/BETA.md)
### Packages

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular",
"version": "5.7.0",
"version": "5.5.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular",
"version": "5.7.0",
"version": "5.5.5",
"license": "MIT",
"dependencies": {
"@ionic/core": "5.6.14",
"@ionic/core": "5.5.4",
"tslib": "^1.9.3"
},
"devDependencies": {
@@ -204,20 +204,14 @@
}
},
"node_modules/@ionic/core": {
"version": "5.6.14",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.14.tgz",
"integrity": "sha512-0LrEofgfA91aqDlXgnOIfC3QrRxazSA4Zu6StQ1ksQqzkYsJLmceaTowl/b72Yt4eaNHUQIVvUvazpoDNp+zRQ==",
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.5.4.tgz",
"integrity": "sha512-IjbGN8vh3XuJ2ulo3BMlMflcWlUhvEGEexr29JKFvb+O4bWKP5sC2fkqSrswrIstOmv7axm7CeIi2MNRkwYwVA==",
"dependencies": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
"ionicons": "^5.1.2",
"tslib": "^1.10.0"
}
},
"node_modules/@ionic/core/node_modules/tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
},
"node_modules/@rollup/plugin-commonjs": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.1.0.tgz",
@@ -297,9 +291,9 @@
}
},
"node_modules/@stencil/core": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.6.0.tgz",
"integrity": "sha512-QsxWayZyusnqSZrlCl81R71rA3KqFjVVQSH4E0rGN15F1GdQaFonKlHLyCOLKLig1zzC+DQkLLiUuocexuvdeQ==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.4.0.tgz",
"integrity": "sha512-gU6+Yyd6O0KrCSS/O6j8KKqmRo+/Dcs2fI0+APCpbAWK+nqhwDISpdnSEfGDCLMoAC08XOZCycBRk2K1VGnEcg==",
"bin": {
"stencil": "bin/stencil"
},
@@ -2033,11 +2027,11 @@
}
},
"node_modules/ionicons": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.0.tgz",
"integrity": "sha512-0DUHTeoIrGSY+KNyNDaQW7v5+mDstjSkjx8dzT925kXKYBDrN3sGs8kUcSSQbTK132U4CbgDEZkn7FDUa9x8Qw==",
"dependencies": {
"@stencil/core": "^2.5.0"
"@stencil/core": "^2.4.0"
}
},
"node_modules/is-accessor-descriptor": {
@@ -5156,20 +5150,12 @@
}
},
"@ionic/core": {
"version": "5.6.14",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.14.tgz",
"integrity": "sha512-0LrEofgfA91aqDlXgnOIfC3QrRxazSA4Zu6StQ1ksQqzkYsJLmceaTowl/b72Yt4eaNHUQIVvUvazpoDNp+zRQ==",
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.5.4.tgz",
"integrity": "sha512-IjbGN8vh3XuJ2ulo3BMlMflcWlUhvEGEexr29JKFvb+O4bWKP5sC2fkqSrswrIstOmv7axm7CeIi2MNRkwYwVA==",
"requires": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
},
"dependencies": {
"tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
}
"ionicons": "^5.1.2",
"tslib": "^1.10.0"
}
},
"@rollup/plugin-commonjs": {
@@ -5243,9 +5229,9 @@
"dev": true
},
"@stencil/core": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.6.0.tgz",
"integrity": "sha512-QsxWayZyusnqSZrlCl81R71rA3KqFjVVQSH4E0rGN15F1GdQaFonKlHLyCOLKLig1zzC+DQkLLiUuocexuvdeQ=="
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.4.0.tgz",
"integrity": "sha512-gU6+Yyd6O0KrCSS/O6j8KKqmRo+/Dcs2fI0+APCpbAWK+nqhwDISpdnSEfGDCLMoAC08XOZCycBRk2K1VGnEcg=="
},
"@szmarczak/http-timer": {
"version": "1.1.2",
@@ -6662,11 +6648,11 @@
"dev": true
},
"ionicons": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.0.tgz",
"integrity": "sha512-0DUHTeoIrGSY+KNyNDaQW7v5+mDstjSkjx8dzT925kXKYBDrN3sGs8kUcSSQbTK132U4CbgDEZkn7FDUa9x8Qw==",
"requires": {
"@stencil/core": "^2.5.0"
"@stencil/core": "^2.4.0"
}
},
"is-accessor-descriptor": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "5.7.0",
"version": "5.5.5",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -42,7 +42,7 @@
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"dependencies": {
"@ionic/core": "5.7.0",
"@ionic/core": "5.5.5",
"tslib": "^1.9.3"
},
"peerDependencies": {

View File

@@ -5,10 +5,16 @@ 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 = {

View File

@@ -1,7 +1,6 @@
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 { componentOnReady } from '@ionic/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
@@ -52,7 +51,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
this._swipeGesture = swipe;
this.nativeEl.swipeHandler = swipe ? {
canStart: () => this.stackCtrl.canGoBack(1) && !this.stackCtrl.hasRunningTask(),
canStart: () => this.stackCtrl.canGoBack(1),
onStart: () => this.stackCtrl.startBackTransition(),
onEnd: shouldContinue => this.stackCtrl.endBackTransition(shouldContinue)
} : undefined;
@@ -97,12 +96,13 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
this.activateWith(context.route, context.resolver || null);
}
}
new Promise(resolve => componentOnReady(this.nativeEl, resolve)).then(() => {
if (this._swipeGesture === undefined) {
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
}
});
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 {
@@ -147,27 +147,15 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
deactivate(): void {
if (this.activated) {
if (this.activatedView) {
const context = this.getContext()!;
this.activatedView.savedData = new Map(context.children['contexts']);
/**
* Angular v11.2.10 introduced a change
* where this route context is cleared out when
* a router-outlet is deactivated, However,
* we need this route information in order to
* return a user back to the correct tab when
* leaving and then going back to the tab context.
*/
const primaryOutlet = this.activatedView.savedData.get('primary');
if (primaryOutlet && context.route) {
primaryOutlet.route = { ...context.route };
}
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;

View File

@@ -232,10 +232,6 @@ export class StackController {
return this.activeView ? this.activeView.stackId : undefined;
}
hasRunningTask(): boolean {
return this.runningTask !== undefined;
}
destroy() {
this.containerEl = undefined!;
this.views.forEach(destroyView);
@@ -298,7 +294,6 @@ export class StackController {
this.runningTask = undefined;
}
const promise = this.runningTask = task();
promise.finally(() => this.runningTask = undefined);
return promise;
}
}

View File

@@ -278,8 +278,8 @@ export class IonHeader {
}
export declare interface IonIcon extends Components.IonIcon {
}
@ProxyCmp({ inputs: ["ariaHidden", "ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] })
@Component({ selector: "ion-icon", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["ariaHidden", "ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] })
@ProxyCmp({ inputs: ["ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "size", "src"] })
@Component({ selector: "ion-icon", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", 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) {
@@ -643,8 +643,8 @@ export class IonRow {
}
export declare interface IonSearchbar extends Components.IonSearchbar {
}
@ProxyCmp({ inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"], "methods": ["setFocus", "getInputElement"] })
@Component({ selector: "ion-searchbar", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] })
@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: "<ng-content></ng-content>", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "placeholder", "searchIcon", "showCancelButton", "spellcheck", "type", "value"] })
export class IonSearchbar {
ionInput!: EventEmitter<CustomEvent>;
ionChange!: EventEmitter<CustomEvent>;

View File

@@ -71,7 +71,7 @@ export declare interface IonVirtualScroll {
* entire virtual scroll is reset, which is an expensive operation and
* should be avoided if possible.
*/
items?: any[] | null;
items?: any[];
/**
* An optional function that maps each item within their height.

View File

@@ -43,47 +43,7 @@ export * from './types/ionic-lifecycle-hooks';
export { IonicModule } from './ionic-module';
// UTILS
export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core';
export { IonicSafeString, getPlatforms, isPlatform, createAnimation } from '@ionic/core';
// CORE TYPES
export {
Animation,
AnimationBuilder,
AnimationCallbackOptions,
AnimationDirection,
AnimationFill,
AnimationKeyFrames,
AnimationLifecycle,
Gesture,
GestureConfig,
GestureDetail,
mdTransitionAnimation,
iosTransitionAnimation,
NavComponentWithProps,
SpinnerTypes,
ActionSheetOptions,
ActionSheetButton,
AlertOptions,
AlertInput,
AlertTextareaAttributes,
AlertInputAttributes,
AlertButton,
LoadingOptions,
ModalOptions,
PickerOptions,
PickerButton,
PickerColumn,
PickerColumnOption,
PopoverOptions,
ToastOptions,
ToastButton
} from '@ionic/core';
export { Animation, AnimationBuilder, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, Gesture, GestureConfig, GestureDetail, mdTransitionAnimation, iosTransitionAnimation, NavComponentWithProps } from '@ionic/core';

View File

@@ -110,7 +110,6 @@ export class Platform {
* | Platform Name | Description |
* |-----------------|------------------------------------|
* | android | on a device running Android. |
* | capacitor | on a device running Capacitor. |
* | cordova | on a device running Cordova. |
* | ios | on a device running iOS. |
* | ipad | on an iPad device. |
@@ -210,7 +209,7 @@ export class Platform {
}
/**
* Returns `true` if the app is in portrait mode.
* Returns `true` if the app is in portait mode.
*/
isPortrait(): boolean {
return this.win.matchMedia && this.win.matchMedia('(orientation: portrait)').matches;

View File

@@ -10,6 +10,6 @@ export interface IonicWindow extends Window {
}
export interface HTMLStencilElement extends HTMLElement {
componentOnReady?(): Promise<this>;
forceUpdate?(): void;
componentOnReady(): Promise<this>;
forceUpdate(): void;
}

View File

@@ -85,6 +85,33 @@
"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": {

View File

@@ -1,8 +0,0 @@
{
"integrationFolder": "./e2e",
"testFiles": "**/*.spec.ts",
"baseUrl": "http://localhost:4200/",
"ignoreTestFiles": "**/examples/*",
"video": false,
"screenshotOnRunFailure": false
}

View File

@@ -1,79 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
Cypress.Commands.add('ionSwipeToGoBack', (complete = false, selector = 'ion-router-outlet') => {
const increment = (complete) ? 60 : 25;
cy.get(selector)
.first()
.trigger('mousedown', 0, 275, { which: 1, force: true })
.trigger('mousemove', increment * 1, 275, { which: 1, force: true })
.wait(50)
.trigger('mousemove', increment * 2, 275, { which: 1, force: true })
.wait(50)
.trigger('mousemove', increment * 3, 275, { which: 1, force: true })
.wait(50)
.trigger('mousemove', increment * 4, 275, { which: 1, force: true })
.wait(50)
.trigger('mouseup', increment * 4, 275, { which: 1, force: true })
cy.wait(150);
})
Cypress.Commands.add('testStack', (selector, expected) => {
cy.document().then((doc) => {
const children = Array.from(
doc.querySelector(selector).children
).map(el => el.tagName.toLowerCase());
expect(children).to.deep.equal(expected);
})
})
Cypress.Commands.add('testLifeCycle', (selector, expected) => {
cy.get(`${selector} #ngOnInit`).invoke('text').should('equal', '1');
cy.get(`${selector} #ionViewWillEnter`).invoke('text').should('equal', expected.ionViewWillEnter.toString());
cy.get(`${selector} #ionViewDidEnter`).invoke('text').should('equal', expected.ionViewDidEnter.toString());
cy.get(`${selector} #ionViewWillLeave`).invoke('text').should('equal', expected.ionViewWillLeave.toString());
cy.get(`${selector} #ionViewDidLeave`).invoke('text').should('equal', expected.ionViewDidLeave.toString());
})
Cypress.Commands.add('ionPageVisible', (selector) => {
cy.get(selector)
.should('have.class', 'ion-page')
.should('not.have.class', 'ion-page-hidden')
.should('not.have.class', 'ion-page-invisible')
.should('have.length', 1)
})
Cypress.Commands.add('ionPageHidden', (selector) => {
cy.get(selector)
.should('have.class', 'ion-page')
.should('have.class', 'ion-page-hidden')
.should('have.length', 1)
})
Cypress.Commands.add('ionPageDoesNotExist', (selector) => {
cy.get(selector)
.should('not.exist')
});

View File

@@ -1,69 +0,0 @@
/// <reference types="cypress" />
declare namespace Cypress {
interface Chainable<Subject> {
/**
* Swipe to go back on the current selector or router outlet
* @example
* ```
* cy.ionSwipeToGoBack();
* cy.ionSwipeToGoBack(true);
* ```
*/
ionSwipeToGoBack(complete: boolean, selector: string): Chainable<any>
/**
* Test that the proper pages are in the navigation stack
* @example
* ```
* cy.testStack('ion-router-outlet', ['app-navigation-page2', 'app-navigation-page1']);
* cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
* ```
*/
testStack(selector: string, expected: string[]): Chainable<any>
/**
* Test whether or not the lifecycle events fired
* @example
* ```
* cy.testLifeCycle('app-router-link-page', {
* ionViewWillEnter: 1,
* ionViewDidEnter: 1,
* ionViewWillLeave: 0,
* ionViewDidLeave: 0,
* });
* ```
*/
testLifeCycle(selector: string, expected: any): Chainable<any>
/**
* Test whether or not an .ion-page element is visible.
* Use this to test a page after navigating to it.
* @example
* ```
* cy.ionPageVisible('app-my-page');
* ```
*/
ionPageVisible(selector: string): Chainable<any>
/**
* Test whether or not an .ion-page element is hidden
* Use this to test a page after navigating away from it.
* @example
* ```
* cy.ionPageHidden('app-my-page');
* ```
*/
ionPageHidden(selector: string): Chainable<any>
/**
* Test whether or not an .ion-page element exists.
* Use this to test a page after popping it off the stack.
* @example
* ```
* cy.ionPageDoesNotExist('app-my-page');
* ```
*/
ionPageDoesNotExist(selector: string): Chainable<any>
}
}

View File

@@ -0,0 +1,14 @@
// Protractor CI configuration file, see link for more information
// https://angular.io/guide/testing#configure-cli-for-ci-testing-in-chrome
const config = require('./protractor.conf').config;
config.capabilities = {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--no-sandbox', '--window-size=1920,1080']
}
};
exports.config = config;

View File

@@ -0,0 +1,35 @@
// @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 } }));
}
};

View File

@@ -0,0 +1,133 @@
import { browser, element, by } from 'protractor';
import { handleErrorMessages, getProperty, setProperty, getText, waitTime } from './utils';
describe('form', () => {
afterEach(() => {
return handleErrorMessages();
});
describe('status updates', () => {
beforeEach(async () => {
await browser.get('/form');
await waitTime(30);
});
it('should update Ionic form classes when calling form methods programatically', async () => {
await element(by.css('form #input-touched')).click();
await waitTime(100);
const classList = (await getProperty('#touched-input-test', 'classList')) as string[];
expect(classList.includes('ion-touched')).toEqual(true);
});
});
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);
}

View File

@@ -1,118 +0,0 @@
describe('Form', () => {
beforeEach(() => {
cy.visit('/form');
})
describe('status updates', () => {
it('should update Ionic form classes when calling form methods programmatically', async () => {
cy.get('#input-touched').click();
cy.get('#touched-input-test').should('have.class', 'ion-touched');
});
});
describe('change', () => {
it('should have default values', () => {
testStatus('INVALID');
cy.get('#submit').should('have.text', 'false');
testData({
datetime: '2010-08-20',
select: null,
toggle: false,
input: '',
input2: 'Default Value',
checkbox: false,
range: 5
});
});
it('should become valid', () => {
cy.get('ion-input.required').invoke('prop', 'value', 'Some value');
testStatus('INVALID');
cy.get('ion-select').invoke('prop', 'value', 'nes');
testStatus('INVALID');
cy.get('ion-range').invoke('prop', 'value', 40);
testStatus('VALID');
testData({
datetime: '2010-08-20',
select: 'nes',
toggle: false,
input: 'Some value',
input2: 'Default Value',
checkbox: false,
range: 40
});
});
it('ion-toggle should change', () => {
cy.get('form ion-toggle').click();
testData({
datetime: '2010-08-20',
select: null,
toggle: true,
input: '',
input2: 'Default Value',
checkbox: false,
range: 5
});
});
it('ion-checkbox should change', () => {
cy.get('ion-checkbox').click();
testData({
datetime: '2010-08-20',
select: null,
toggle: false,
input: '',
input2: 'Default Value',
checkbox: true,
range: 5
});
});
it('should submit', () => {
cy.get('#set-values').click();
cy.get('#submit-button').click();
cy.get('#submit').should('have.text', 'true');
});
});
describe('blur', () => {
it('ion-toggle should change only after blur', () => {
cy.get('form ion-toggle').click();
testData({
datetime: '2010-08-20',
select: null,
toggle: true,
input: '',
input2: 'Default Value',
checkbox: false,
range: 5
});
cy.get('ion-checkbox').click();
testData({
datetime: '2010-08-20',
select: null,
toggle: true,
input: '',
input2: 'Default Value',
checkbox: true,
range: 5
});
});
});
});
function testStatus(status) {
cy.get('#status').should('have.text', status);
}
function testData(data) {
cy.get('#data').invoke('text').then(text => {
const value = JSON.parse(text);
console.log(value, data);
expect(value).to.deep.equal(data);
})
}

View File

@@ -0,0 +1,69 @@
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');
});
});

View File

@@ -1,61 +0,0 @@
describe('Inputs', () => {
beforeEach(() => {
cy.visit('/inputs');
})
it('should have default value', () => {
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
cy.get('ion-select').should('have.prop', 'value').and('equal', 'nes');
cy.get('ion-range').should('have.prop', 'value').and('equal', 10);
});
it('should have reset value', () => {
cy.get('#reset-button').click();
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', false);
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', false);
cy.get('ion-input').should('have.prop', 'value').and('equal', '');
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '');
cy.get('ion-select').should('have.prop', 'value').and('equal', '');
cy.get('ion-range').should('have.prop', 'value').and('be.NaN');
});
it('should get some value', () => {
cy.get('#reset-button').click();
cy.get('#set-button').click();
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', true);
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', true);
cy.get('ion-input').should('have.prop', 'value').and('equal', 'some text');
cy.get('ion-datetime').should('have.prop', 'value').and('equal', '1994-03-15');
cy.get('ion-select').should('have.prop', 'value').and('equal', 'nes');
cy.get('ion-range').should('have.prop', 'value').and('equal', 10);
});
it('change values should update angular', () => {
cy.get('#reset-button').click();
cy.get('ion-checkbox').invoke('prop', 'checked', true);
cy.get('ion-toggle').invoke('prop', 'checked', true);
cy.get('ion-input').invoke('prop', 'value', 'hola');
cy.get('ion-datetime').invoke('prop', 'value', '1996-03-15');
cy.get('ion-select').invoke('prop', 'value', 'playstation');
cy.get('ion-range').invoke('prop', 'value', 20);
cy.get('#checkbox-note').should('have.text', 'true');
cy.get('#toggle-note').should('have.text', 'true');
cy.get('#input-note').should('have.text', 'hola');
cy.get('#datetime-note').should('have.text', '1996-03-15');
cy.get('#select-note').should('have.text', 'playstation');
cy.get('#range-note').should('have.text', '20');
});
it('nested components should not interfere with NgModel', () => {
cy.get('#range-note').should('have.text', '10');
cy.get('#nested-toggle').click();
cy.get('#range-note').should('have.text', '10');
});
})

View File

@@ -0,0 +1,55 @@
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');
});
});

View File

@@ -1,43 +0,0 @@
describe('Modals', () => {
beforeEach(() => {
cy.visit('/modals');
})
it('should open standalone modal and close', () => {
cy.get('#action-button').click();
cy.get('ion-modal').should('exist').should('be.visible');
cy.get('app-modal-example h2').should('have.text', '123');
cy.get('app-modal-example h3').should('have.text', '321');
cy.get('#onWillDismiss').should('have.text', 'false');
cy.get('#onDidDismiss').should('have.text', 'false');
cy.get('#close-modal').click();
cy.get('ion-modal').should('not.exist');
cy.get('#onWillDismiss').should('have.text', 'true');
cy.get('#onDidDismiss').should('have.text', 'true');
});
it('should open nav modal and close', () => {
cy.get('#action-button-2').click();
cy.get('ion-modal').should('exist').should('be.visible');
cy.get('ion-nav > *:last-child h2').should('have.text', '123');
cy.get('ion-nav > *:last-child h3').should('have.text', '321');
cy.get('ion-nav > *:last-child .push-page').click();
cy.get('ion-nav > *:last-child h2').should('have.text', 'pushed!');
cy.get('ion-nav > *:last-child h3').should('have.text', '');
cy.get('ion-nav > *:last-child .pop-page').click();
cy.get('ion-nav > *:last-child h2').should('have.text', '123');
});
});

View File

@@ -0,0 +1,73 @@
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();
}

View File

@@ -1,18 +0,0 @@
describe('Navigation', () => {
beforeEach(() => {
cy.visit('/navigation');
})
it('should navigate correctly', () => {
cy.visit('/navigation/page1');
cy.wait(2000);
cy.testStack('ion-router-outlet', ['app-navigation-page2', 'app-navigation-page1']);
cy.get('app-navigation-page2').should('have.attr', 'aria-hidden').and('equal', 'true');
cy.get('app-navigation-page2').should('have.attr', 'class').and('equal', 'ion-page ion-page-hidden');
cy.get('app-navigation-page1').should('not.have.attr', 'aria-hidden');
cy.get('app-navigation-page1').should('have.attr', 'class').and('equal', 'ion-page can-go-back');
});
})

View File

@@ -0,0 +1,23 @@
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');
});
});

View File

@@ -1,25 +0,0 @@
describe('Nested Outlet', () => {
beforeEach(() => {
cy.visit('/nested-outlet/page');
})
it('should navigate correctly', () => {
cy.get('ion-router-outlet ion-router-outlet app-nested-outlet-page h1').should('have.text', 'Nested page 1');
cy.get('#goto-tabs').click();
cy.ionPageVisible('app-tabs');
cy.ionPageVisible('app-tabs-tab1');
cy.get('#goto-nested-page1').click();
cy.ionPageVisible('app-nested-outlet-page');
cy.ionPageDoesNotExist('app-tabs');
cy.get('#goto-nested-page2').click();
cy.ionPageVisible('app-nested-outlet-page2');
cy.get('ion-router-outlet ion-router-outlet app-nested-outlet-page2 h1').should('have.text', 'Nested page 2');
});
});

View File

@@ -0,0 +1,29 @@
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');
});
});

View File

@@ -1,24 +0,0 @@
describe('Providers', () => {
beforeEach(() => {
cy.visit('/providers');
})
it('should load all providers', () => {
cy.get('#is-loaded').should('have.text', 'true');
cy.get('#is-ready').should('have.text', 'true');
cy.get('#is-paused').should('have.text', 'true');
cy.get('#is-resumed').should('have.text', 'true');
cy.get('#is-resized').should('have.text', 'true');
cy.get('#is-testing').should('have.text', 'false');
cy.get('#is-desktop').should('have.text', 'true');
cy.get('#is-mobile').should('have.text', 'false');
cy.get('#keyboard-height').should('have.text', '12345');
});
it('should detect testing mode', () => {
cy.visit('/providers?ionic:_testing=true');
cy.get('#is-testing').should('have.text', 'true');
});
});

View File

@@ -0,0 +1,194 @@
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,
});
}

View File

@@ -1,192 +0,0 @@
describe('Router Link', () => {
beforeEach(() => {
cy.visit('/router-link');
});
describe('router-link params and fragments', () => {
const queryParam = 'A&=#Y';
const fragment = 'myDiv1';
const id = 'MyPageID==';
it('should go to a page with properly encoded values', () => {
cy.visit('/router-link?ionic:_testing=true');
cy.get('#queryParamsFragment').click();
const expectedPath = `${encodeURIComponent(id)}`;
const expectedSearch = `?token=${encodeURIComponent(queryParam)}`;
const expectedHash = `#${encodeURIComponent(fragment)}`;
cy.location().should((location) => {
expect(location.pathname).to.contain(expectedPath);
expect(location.search).to.eq(expectedSearch);
expect(location.hash).to.eq(expectedHash);
});
});
it('should return to a page with preserved query param and fragment', () => {
cy.visit('/router-link?ionic:_testing=true');
cy.get('#queryParamsFragment').click();
cy.get('#goToPage3').click();
cy.location().should((location) => {
expect(location.pathname).to.contain('router-link-page3');
});
cy.get('#goBackFromPage3').click();
const expectedPath = `${encodeURIComponent(id)}`;
const expectedSearch = `?token=${encodeURIComponent(queryParam)}`;
const expectedHash = `#${encodeURIComponent(fragment)}`;
cy.location().should((location) => {
expect(location.pathname).to.contain(expectedPath);
expect(location.search).to.eq(expectedSearch);
expect(location.hash).to.eq(expectedHash);
});
});
it('should preserve query param and fragment with defaultHref string', () => {
cy.visit('/router-link-page3?ionic:_testing=true');
cy.get('#goBackFromPage3').click();
const expectedSearch = '?token=ABC';
const expectedHash = '#fragment';
cy.location().should((location) => {
expect(location.search).to.eq(expectedSearch);
expect(location.hash).to.eq(expectedHash);
});
});
});
describe('router-link', () => {
it('should have correct lifecycle counts', () => {
cy.testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
});
});
describe('forward', () => {
it('should go forward with ion-button[routerLink]', () => {
cy.get('#routerLink').click();
testForward();
});
it('should go forward with a[routerLink]', () => {
cy.get('#a').click();
testForward();
});
it('should go forward with button + navigateByUrl()', () => {
cy.get('#button').click();
testForward();
});
it('should go forward with button + navigateForward()', () => {
cy.get('#button-forward').click();
testForward();
});
});
describe('root', () => {
it('should go root with ion-button[routerLink][routerDirection=root]', () => {
cy.get('#routerLink-root').click();
testRoot();
});
it('should go root with a[routerLink][routerDirection=root]', () => {
cy.get('#a-root').click();
testRoot();
});
it('should go root with button + navigateRoot', () => {
cy.get('#button-root').click();
testRoot();
});
});
describe('back', () => {
it('should go back with ion-button[routerLink][routerDirection=back]', () => {
cy.get('#routerLink-back').click();
});
it('should go back with a[routerLink][routerDirection=back]', () => {
cy.get('#a-back').click();
testBack();
});
it('should go back with button + navigateBack', () => {
cy.get('#button-back').click();
testBack();
});
});
});
function testForward() {
cy.testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
cy.testLifeCycle('app-router-link-page', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
cy.get('app-router-link-page #canGoBack').should('have.text', 'true');
cy.go('back');
cy.testStack('ion-router-outlet', ['app-router-link']);
cy.testLifeCycle('app-router-link', {
ionViewWillEnter: 2,
ionViewDidEnter: 2,
ionViewWillLeave: 1,
ionViewDidLeave: 1,
});
}
function testRoot() {
cy.wait(200);
cy.testStack('ion-router-outlet', ['app-router-link-page']);
cy.testLifeCycle('app-router-link-page', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
cy.get('app-router-link-page #canGoBack').should('have.text', 'false');
cy.go('back');
cy.wait(100);
cy.testStack('ion-router-outlet', ['app-router-link']);
cy.testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
}
function testBack() {
cy.wait(500);
cy.testStack('ion-router-outlet', ['app-router-link-page']);
cy.testLifeCycle('app-router-link-page', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
cy.get('app-router-link-page #canGoBack').should('have.text', 'false');
cy.go('back');
cy.wait(100);
cy.testStack('ion-router-outlet', ['app-router-link']);
cy.testLifeCycle('app-router-link', {
ionViewWillEnter: 1,
ionViewDidEnter: 1,
ionViewWillLeave: 0,
ionViewDidLeave: 0,
});
}

View File

@@ -1,36 +0,0 @@
describe('Routing', () => {
beforeEach(() => {
cy.visit('/router-link?ionic:mode=ios');
})
it('should swipe and abort', () => {
cy.get('#routerLink').click();
cy.ionSwipeToGoBack();
cy.get('app-router-link').should('have.attr', 'aria-hidden').and('equal', 'true');
cy.get('app-router-link').should('have.attr', 'class').and('equal', 'ion-page ion-page-hidden');
cy.get('app-router-link-page').should('not.have.attr', 'aria-hidden');
cy.get('app-router-link-page').should('have.attr', 'class').and('equal', 'ion-page can-go-back');
});
it('should swipe and go back', () => {
cy.get('#routerLink').click();
cy.ionPageHidden('app-router-link');
cy.ionPageVisible('app-router-link-page');
cy.testStack('ion-router-outlet', ['app-router-link', 'app-router-link-page']);
cy.ionSwipeToGoBack(true);
cy.ionPageVisible('app-router-link');
cy.ionPageDoesNotExist('app-router-link-page');
cy.testStack('ion-router-outlet', ['app-router-link']);
cy.get('app-router-link').should('not.have.attr', 'aria-hidden');
cy.get('app-router-link').should('have.attr', 'class').and('equal', 'ion-page');
});
})

View File

@@ -0,0 +1,51 @@
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);
}

View File

@@ -1,44 +0,0 @@
describe('Slides', () => {
beforeEach(() => {
cy.visit('/slides');
cy.wait(30);
})
it('should change index on slide change', () => {
cy.get('ion-slide').should('have.length', 0);
cy.get('#add-slides').click();
cy.get('ion-slide').should('have.length', 3);
// Should be on the first slide
checkIndex('0');
// Swipe to the second slide
nextSlide();
checkIndex('1');
// Swipe to the third slide
nextSlide();
checkIndex('2');
// Go back to the second slide
prevSlide();
checkIndex('1');
});
});
function checkIndex(index) {
cy.get('#slide-index').should('have.text', index);
cy.get('#slide-index-2').should('have.text', index);
}
function nextSlide() {
cy.get('#btn-next').click();
cy.wait(800);
}
function prevSlide() {
cy.get('#btn-prev').click();
cy.wait(800);
}

View File

@@ -0,0 +1,334 @@
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';
const 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);
const 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<ElementFinder> {
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;
}

View File

@@ -1,329 +0,0 @@
describe('Tabs', () => {
beforeEach(() => {
cy.visit('/tabs');
})
describe('entry url - /tabs', () => {
it('should redirect and load tab-account', () => {
testTabTitle('Tab 1 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1']);
testState(1, 'account');
});
it('should navigate between tabs and ionChange events should be dispatched', () => {
let tab = testTabTitle('Tab 1 - Page 1');
tab.find('.segment-changed').should('have.text', 'false');
cy.get('#tab-button-contact').click();
tab = testTabTitle('Tab 2 - Page 1');
tab.find('.segment-changed').should('have.text', 'false');
});
it('should simulate stack + double tab click', () => {
let tab = getSelectedTab();
tab.find('#goto-tab1-page2').click();
testTabTitle('Tab 1 - Page 2 (1)');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']);
testState(1, 'account');
// When you call find on tab above it changes the value of tab
// so we need to redefine it
tab = getSelectedTab();
tab.find('ion-back-button').should('be.visible');
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
testState(2, 'contact');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 2 (1)');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
testState(3, 'account');
tab = getSelectedTab();
tab.find('ion-back-button').should('be.visible');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
testState(3, 'account');
});
it('should simulate stack + back button click', () => {
const tab = getSelectedTab();
tab.find('#goto-tab1-page2').click();
testTabTitle('Tab 1 - Page 2 (1)');
testState(1, 'account');
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
testState(2, 'contact');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 2 (1)');
testState(3, 'account');
cy.get('ion-back-button').click();
testTabTitle('Tab 1 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
testState(3, 'account');
});
it('should navigate deep then go home', () => {
const tab = getSelectedTab();
tab.find('#goto-tab1-page2').click();
testTabTitle('Tab 1 - Page 2 (1)');
cy.get('#goto-next').click();
testTabTitle('Tab 1 - Page 2 (2)');
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 2 (2)');
cy.testStack('ion-tabs ion-router-outlet', [
'app-tabs-tab1',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab2'
]);
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', [
'app-tabs-tab1',
'app-tabs-tab2'
]);
});
it('should switch tabs and go back', () => {
cy.get('#tab-button-contact').click();
const tab = testTabTitle('Tab 2 - Page 1');
tab.find('#goto-tab1-page1').click();
testTabTitle('Tab 1 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']);
});
it('should switch tabs and go to nested', () => {
cy.get('#tab-button-contact').click();
const tab = testTabTitle('Tab 2 - Page 1');
tab.find('#goto-tab1-page2').click();
testTabTitle('Tab 1 - Page 2 (1)');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']);
});
it('should load lazy loaded tab', () => {
cy.get('#tab-button-lazy').click();
cy.ionPageVisible('app-tabs-tab3');
testTabTitle('Tab 3 - Page 1');
});
it('should use ion-back-button defaultHref', () => {
let tab = getSelectedTab();
tab.find('#goto-tab3-page2').click();
testTabTitle('Tab 3 - Page 2');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3-nested']);
tab = getSelectedTab();
tab.find('ion-back-button').click();
testTabTitle('Tab 3 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3']);
});
it('should preserve navigation extras when switching tabs', () => {
const expectUrlToContain = 'search=hello#fragment';
let tab = getSelectedTab();
tab.find('#goto-nested-page1-with-query-params').click();
testTabTitle('Tab 1 - Page 2 (1)');
testUrlContains(expectUrlToContain);
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
cy.get('#tab-button-account').click();
tab = testTabTitle('Tab 1 - Page 2 (1)');
testUrlContains(expectUrlToContain);
});
it('should set root when clicking on an active tab to navigate to the root', () => {
const expectNestedTabUrlToContain = 'search=hello#fragment';
cy.url().then(url => {
const tab = getSelectedTab();
tab.find('#goto-nested-page1-with-query-params').click();
testTabTitle('Tab 1 - Page 2 (1)');
testUrlContains(expectNestedTabUrlToContain);
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
testUrlEquals(url);
})
});
})
describe('entry tab contains navigation extras', () => {
const expectNestedTabUrlToContain = 'search=hello#fragment';
const rootUrlParams = 'test=123#rootFragment';
const rootUrl = `/tabs/account?${rootUrlParams}`;
beforeEach(() => {
cy.visit(rootUrl);
})
it('should preserve root url navigation extras when clicking on an active tab to navigate to the root', () => {
const tab = getSelectedTab();
tab.find('#goto-nested-page1-with-query-params').click();
testTabTitle('Tab 1 - Page 2 (1)');
testUrlContains(expectNestedTabUrlToContain);
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
testUrlContains(rootUrl);
});
it('should preserve root url navigation extras when changing tabs', () => {
getSelectedTab();
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
testUrlContains(rootUrl);
});
it('should navigate deep then go home and preserve navigation extras', () => {
let tab = getSelectedTab();
tab.find('#goto-tab1-page2').click();
tab = testTabTitle('Tab 1 - Page 2 (1)');
tab.find('#goto-next').click();
testTabTitle('Tab 1 - Page 2 (2)');
cy.get('#tab-button-contact').click();
testTabTitle('Tab 2 - Page 1');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 2 (2)');
cy.get('#tab-button-account').click();
testTabTitle('Tab 1 - Page 1');
testUrlContains(rootUrl);
});
})
describe('entry url - /tabs/account/nested/1', () => {
beforeEach(() => {
cy.visit('/tabs/account/nested/1');
})
it('should only display the back-button when there is a page in the stack', () => {
let tab = getSelectedTab();
tab.find('ion-back-button').should('not.be.visible');
testTabTitle('Tab 1 - Page 2 (1)');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
cy.get('#tab-button-account').click();
tab = testTabTitle('Tab 1 - Page 1');
tab.find('#goto-tab1-page2').click();
tab = testTabTitle('Tab 1 - Page 2 (1)');
tab.find('ion-back-button').should('be.visible');
});
it('should not reuse the same page', () => {
let tab = testTabTitle('Tab 1 - Page 2 (1)');
tab.find('#goto-next').click();
tab = testTabTitle('Tab 1 - Page 2 (2)');
tab.find('#goto-next').click();
tab = testTabTitle('Tab 1 - Page 2 (3)');
cy.testStack('ion-tabs ion-router-outlet', [
'app-tabs-tab1-nested',
'app-tabs-tab1-nested',
'app-tabs-tab1-nested'
]);
tab = getSelectedTab();
tab.find('ion-back-button').click();
tab = testTabTitle('Tab 1 - Page 2 (2)');
tab.find('ion-back-button').click();
tab = testTabTitle('Tab 1 - Page 2 (1)');
tab.find('ion-back-button').should('not.be.visible');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
});
})
describe('entry url - /tabs/lazy', () => {
beforeEach(() => {
cy.visit('/tabs/lazy');
});
it('should not display the back-button if coming from a different stack', () => {
let tab = testTabTitle('Tab 3 - Page 1');
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']);
tab = getSelectedTab();
tab.find('#goto-tab1-page2').click();
cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']);
tab = testTabTitle('Tab 1 - Page 2 (1)');
tab.find('ion-back-button').should('not.be.visible');
});
})
describe('enter url - /tabs/contact/one', () => {
beforeEach(() => {
cy.visit('/tabs/contact/one');
});
it('should return to correct tab after going to page in different outlet', () => {
const tab = getSelectedTab();
tab.find('#goto-nested-page1').click();
cy.testStack('app-nested-outlet ion-router-outlet', ['app-nested-outlet-page']);
const nestedOutlet = cy.get('app-nested-outlet');
nestedOutlet.find('ion-back-button').click();
testTabTitle('Tab 2 - Page 1');
});
})
})
function testTabTitle(title) {
const tab = getSelectedTab();
// Find is used to get a direct descendant instead of get
tab.find('ion-title').should('have.text', title);
return getSelectedTab();
}
function getSelectedTab() {
cy.get('ion-tabs ion-router-outlet > *:not(.ion-page-hidden)').should('have.length', 1);
return cy.get('ion-tabs ion-router-outlet > *:not(.ion-page-hidden)').first();
}
function testState(count, tab) {
cy.get('#tabs-state').should('have.text', `${count}.${tab}`);
}
function testUrlContains(urlFragment) {
cy.location().should((location) => {
expect(location.href).to.contain(urlFragment);
});
}
function testUrlEquals(url) {
cy.url().should('eq', url);
}

View File

@@ -0,0 +1,73 @@
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(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);
}

View File

@@ -0,0 +1,22 @@
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');
});
});

View File

@@ -1,14 +0,0 @@
describe('View Child', () => {
beforeEach(() => {
cy.visit('/view-child');
})
it('should get a reference to all children', () => {
// button should be red
cy.get('#color-button').should('have.class', 'ion-color-danger');
// tabs should be found
cy.get('#tabs-result').should('have.text', 'all found');
});
});

View File

@@ -0,0 +1,18 @@
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);
});
});

View File

@@ -1,14 +0,0 @@
describe('Virtual Scroll', () => {
beforeEach(() => {
cy.visit('/virtual-scroll');
cy.wait(30);
})
it('should open virtual-scroll', () => {
cy.document().then((doc) => {
const virtualElements = doc.querySelectorAll('ion-virtual-scroll > *');
expect(virtualElements.length).to.be.greaterThan(0);
});
});
});

View File

@@ -4,17 +4,14 @@
"strictMetadataEmit" : true
},
"extends": "../tsconfig.json",
"include": [
"src/**spec.ts",
"../cypress/support/index.d.ts"
],
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"cypress",
"jasmine",
"jasminewd2",
"node"
]
}
}
}

View File

@@ -0,0 +1,38 @@
// 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'],
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
singleRun: false,
restartOnFileChange: true
});
};

View File

File diff suppressed because it is too large Load Diff

View File

@@ -8,53 +8,60 @@
"sync:build": "sh scripts/build-ionic.sh",
"sync": "sh scripts/sync.sh",
"build": "npm run sync && ng build --prod --no-progress",
"pretest": "webdriver-manager update --versions.chrome 87.0.4280.20",
"test": "ng e2e --prod --webdriver-update=false",
"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",
"cy.open": "cypress open",
"cy.run": "cypress run",
"test": "concurrently \"npm run start\" \"wait-on http-get://localhost:4200 && npm run cy.run\" --kill-others --success first",
"test.watch": "concurrently \"npm run start\" \"wait-on http-get://localhost:4200 && npm run cy.open\" --kill-others --success first"
"prerender": "ng run test-app:prerender"
},
"dependencies": {
"@angular/animations": "^11.2.11",
"@angular/common": "^11.2.11",
"@angular/compiler": "^11.2.11",
"@angular/core": "^11.2.11",
"@angular/forms": "^11.2.11",
"@angular/platform-browser": "^11.2.11",
"@angular/platform-browser-dynamic": "^11.2.11",
"@angular/platform-server": "^11.2.11",
"@angular/router": "^11.2.11",
"@angular/animations": "^9.1.12",
"@angular/common": "^9.1.12",
"@angular/compiler": "^9.1.12",
"@angular/core": "^9.1.12",
"@angular/forms": "^9.1.12",
"@angular/platform-browser": "^9.1.12",
"@angular/platform-browser-dynamic": "^9.1.12",
"@angular/platform-server": "^9.1.12",
"@angular/router": "^9.1.12",
"@ionic/angular": "^5.3.1",
"@ionic/angular-server": "^5.3.1",
"@nguniversal/express-engine": "^11.2.1",
"@nguniversal/express-engine": "9.0.0-next.9",
"angular-in-memory-web-api": "^0.11.0",
"core-js": "^2.6.11",
"express": "^4.15.2",
"jasmine-marbles": "^0.6.0",
"rxjs": "^6.5.5",
"tslib": "^2.0.0",
"tslib": "^1.13.0",
"zone.js": "^0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.1102.10",
"@angular/cli": "^11.2.10",
"@angular/compiler-cli": "^11.2.11",
"@angular/language-service": "^11.2.11",
"@nguniversal/builders": "^11.2.1",
"@angular-devkit/build-angular": "^0.901.12",
"@angular/cli": "^9.1.12",
"@angular/compiler-cli": "^9.1.12",
"@angular/language-service": "^9.1.12",
"@nguniversal/builders": "9.0.0-next.9",
"@types/express": "^4.17.7",
"@types/jasmine": "^3.5.13",
"@types/jasminewd2": "^2.0.8",
"@types/node": "^12.12.54",
"codelyzer": "^6.0.1",
"concurrently": "^6.0.0",
"cypress": "^6.7.1",
"codelyzer": "^5.2.2",
"jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^4.4.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1",
"karma-jasmine": "^3.0.3",
"karma-jasmine-html-reporter": "^1.5.4",
"protractor": "^5.4.4",
"ts-loader": "^6.2.2",
"ts-node": "^8.3.0",
"tslint": "~6.1.0",
"typescript": "^4.0.7",
"wait-on": "^5.2.1",
"tslint": "^6.1.3",
"typescript": "^3.8.3",
"webpack-cli": "^3.3.12"
}
}

View File

@@ -27,7 +27,6 @@ export class ModalComponent {
async open(TheModalComponent: any) {
const modal = await this.modalCtrl.create({
component: TheModalComponent,
animated: false,
componentProps: {
value: '123',
prop: '321'
@@ -41,7 +40,7 @@ export class ModalComponent {
modal.onDidDismiss().then(() => {
NgZone.assertInAngularZone();
if (!this.onWillDismiss) {
throw new Error('onWillDismiss should be emitted first');
throw new Error('onWillDismiss should be emited first');
}
this.onDidDismiss = true;
});

View File

@@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@@ -6,7 +6,7 @@
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"module": "es2020",
"module": "esnext",
"target": "es2015",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,

View File

@@ -2,7 +2,7 @@
"extends": "./tsconfig.app.json",
"compilerOptions": {
"outDir": "./out-tsc/app-server",
"target": "es2016",
"module": "commonjs",
"types": [
"node"
]

View File

@@ -3,6 +3,7 @@
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node"
]
},

View File

@@ -2,37 +2,16 @@
"extends": "tslint:recommended",
"rulesDirectory": ["codelyzer"],
"rules": {
"align": {
"options": [
"parameters",
"statements"
]
},
"array-type": false,
"arrow-parens": false,
"arrow-return-shorthand": true,
"deprecation": {
"severity": "warn"
},
"import-blacklist": [
true,
"rxjs/Rx"
],
"curly": true,
"import-blacklist": [true, "rxjs/Rx"],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
true,
140
],
"eofline": true,
"max-line-length": [true, 140],
"member-access": false,
"import-spacing": true,
"indent": {
"options": [
"spaces"
]
},
"member-ordering": [
true,
{
@@ -51,6 +30,7 @@
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
@@ -66,68 +46,9 @@
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"one-variable-per-declaration": false,
"component-class-suffix": [
true,
"Page",
"Component"
],
"semicolon": {
"options": [
"always"
]
},
"space-before-function-paren": {
"options": {
"anonymous": "never",
"asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
},
"component-class-suffix": [true, "Page", "Component"],
"directive-class-suffix": true,
"typedef-whitespace": {
"options": [
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
},
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [
true,
"element",
"app",
"page",
"kebab-case"
],
"variable-name": {
"options": [
"ban-keywords",
"check-format",
"allow-pascal-case"
]
},
"whitespace": {
"options": [
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
}
"component-selector": [true, "element", "app", "page", "kebab-case"]
}
}

View File

@@ -1,3 +0,0 @@
module.exports = {
extends: ['@commitlint/config-conventional']
}

View File

@@ -254,7 +254,7 @@ rules:
- visibility
- z-index
property-disallowed-list:
property-blacklist:
- background-position
- right
- left

View File

@@ -40,24 +40,6 @@ The `@ionic/core` package can by used in simple HTML, or by vanilla JavaScript w
* [@ionic/angular](https://www.npmjs.com/package/@ionic/angular)
## Custom Elements Build (Experimental)
In addition to the default, self lazy-loading components built by Stencil, this package also comes with each component exported as a stand-alone custom element within `@ionic/core/components`. Each component extends `HTMLElement`, and does not lazy-load itself. Instead, this package is useful for projects already using a bundler such as Webpack or Rollup. While all components are available to be imported, the custom elements build also ensures bundlers only import what's used, and tree-shakes any unused components.
Below is an example of importing `ion-toggle`, and initializing Ionic so it's able to correctly load the "mode", such as Material Design or iOS. Additionally, the `initialize({...})` function can receive the Ionic config.
```typescript
import { IonBadge } from "@ionic/core/components/ion-badge";
import { initialize } from "@ionic/core/components";
initialize();
customElements.define("ion-badge", IonBadge);
```
Notice how `IonBadge` is imported from `@ionic/core/components/ion-badge` rather than just `@ionic/core/components`. Additionally, the `initialize` function is imported from `@ionic/core/components` rather than `@ionic/core`. All of this helps to ensure bundlers do not pull in more code than is needed.
## How to contribute
[Check out the CONTRIBUTE guide](CONTRIBUTING.md)

View File

@@ -80,7 +80,7 @@ ion-avatar,shadow
ion-avatar,css-prop,--border-radius
ion-back-button,shadow
ion-back-button,prop,color,string | undefined,undefined,false,true
ion-back-button,prop,color,string | undefined,undefined,false,false
ion-back-button,prop,defaultHref,string | undefined,undefined,false,false
ion-back-button,prop,disabled,boolean,false,false,true
ion-back-button,prop,icon,null | string | undefined,undefined,false,false
@@ -131,7 +131,7 @@ ion-backdrop,prop,visible,boolean,true,false,false
ion-backdrop,event,ionBackdropTap,void,true
ion-badge,shadow
ion-badge,prop,color,string | undefined,undefined,false,true
ion-badge,prop,color,string | undefined,undefined,false,false
ion-badge,prop,mode,"ios" | "md",undefined,false,false
ion-badge,css-prop,--background
ion-badge,css-prop,--color
@@ -142,7 +142,7 @@ ion-badge,css-prop,--padding-top
ion-button,shadow
ion-button,prop,buttonType,string,'button',false,false
ion-button,prop,color,string | undefined,undefined,false,true
ion-button,prop,color,string | undefined,undefined,false,false
ion-button,prop,disabled,boolean,false,false,true
ion-button,prop,download,string | undefined,undefined,false,false
ion-button,prop,expand,"block" | "full" | undefined,undefined,false,true
@@ -189,7 +189,7 @@ ion-buttons,prop,collapse,boolean,false,false,false
ion-card,shadow
ion-card,prop,button,boolean,false,false,false
ion-card,prop,color,string | undefined,undefined,false,true
ion-card,prop,color,string | undefined,undefined,false,false
ion-card,prop,disabled,boolean,false,false,false
ion-card,prop,download,string | undefined,undefined,false,false
ion-card,prop,href,string | undefined,undefined,false,false
@@ -207,30 +207,30 @@ ion-card-content,none
ion-card-content,prop,mode,"ios" | "md",undefined,false,false
ion-card-header,shadow
ion-card-header,prop,color,string | undefined,undefined,false,true
ion-card-header,prop,color,string | undefined,undefined,false,false
ion-card-header,prop,mode,"ios" | "md",undefined,false,false
ion-card-header,prop,translucent,boolean,false,false,false
ion-card-subtitle,shadow
ion-card-subtitle,prop,color,string | undefined,undefined,false,true
ion-card-subtitle,prop,color,string | undefined,undefined,false,false
ion-card-subtitle,prop,mode,"ios" | "md",undefined,false,false
ion-card-subtitle,css-prop,--color
ion-card-title,shadow
ion-card-title,prop,color,string | undefined,undefined,false,true
ion-card-title,prop,color,string | undefined,undefined,false,false
ion-card-title,prop,mode,"ios" | "md",undefined,false,false
ion-card-title,css-prop,--color
ion-checkbox,shadow
ion-checkbox,prop,checked,boolean,false,false,false
ion-checkbox,prop,color,string | undefined,undefined,false,true
ion-checkbox,prop,color,string | undefined,undefined,false,false
ion-checkbox,prop,disabled,boolean,false,false,false
ion-checkbox,prop,indeterminate,boolean,false,false,false
ion-checkbox,prop,mode,"ios" | "md",undefined,false,false
ion-checkbox,prop,name,string,this.inputId,false,false
ion-checkbox,prop,value,string,'on',false,false
ion-checkbox,event,ionBlur,void,true
ion-checkbox,event,ionChange,CheckboxChangeEventDetail<any>,true
ion-checkbox,event,ionChange,CheckboxChangeEventDetail,true
ion-checkbox,event,ionFocus,void,true
ion-checkbox,css-prop,--background
ion-checkbox,css-prop,--background-checked
@@ -247,7 +247,7 @@ ion-checkbox,part,container
ion-checkbox,part,mark
ion-chip,shadow
ion-chip,prop,color,string | undefined,undefined,false,true
ion-chip,prop,color,string | undefined,undefined,false,false
ion-chip,prop,disabled,boolean,false,false,false
ion-chip,prop,mode,"ios" | "md",undefined,false,false
ion-chip,prop,outline,boolean,false,false,false
@@ -288,7 +288,7 @@ ion-col,css-prop,--ion-grid-column-padding-xs
ion-col,css-prop,--ion-grid-columns
ion-content,shadow
ion-content,prop,color,string | undefined,undefined,false,true
ion-content,prop,color,string | undefined,undefined,false,false
ion-content,prop,forceOverscroll,boolean | undefined,undefined,false,false
ion-content,prop,fullscreen,boolean,false,false,false
ion-content,prop,scrollEvents,boolean,false,false,false
@@ -333,7 +333,7 @@ ion-datetime,prop,monthShortNames,string | string[] | undefined,undefined,false,
ion-datetime,prop,monthValues,number | number[] | string | undefined,undefined,false,false
ion-datetime,prop,name,string,this.inputId,false,false
ion-datetime,prop,pickerFormat,string | undefined,undefined,false,false
ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; showBackdrop?: boolean | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: Mode | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; showBackdrop?: boolean | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: "ios" | "md" | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
ion-datetime,prop,placeholder,null | string | undefined,undefined,false,false
ion-datetime,prop,readonly,boolean,false,false,false
ion-datetime,prop,value,null | string | undefined,undefined,false,false
@@ -361,7 +361,7 @@ ion-fab,method,close,close() => Promise<void>
ion-fab-button,shadow
ion-fab-button,prop,activated,boolean,false,false,false
ion-fab-button,prop,closeIcon,string,'close',false,false
ion-fab-button,prop,color,string | undefined,undefined,false,true
ion-fab-button,prop,color,string | undefined,undefined,false,false
ion-fab-button,prop,disabled,boolean,false,false,false
ion-fab-button,prop,download,string | undefined,undefined,false,false
ion-fab-button,prop,href,string | undefined,undefined,false,false
@@ -457,7 +457,7 @@ ion-input,prop,autocorrect,"off" | "on",'off',false,false
ion-input,prop,autofocus,boolean,false,false,false
ion-input,prop,clearInput,boolean,false,false,false
ion-input,prop,clearOnEdit,boolean | undefined,undefined,false,false
ion-input,prop,color,string | undefined,undefined,false,true
ion-input,prop,color,string | undefined,undefined,false,false
ion-input,prop,debounce,number,0,false,false
ion-input,prop,disabled,boolean,false,false,false
ion-input,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
@@ -497,7 +497,7 @@ ion-input,css-prop,--placeholder-opacity
ion-item,shadow
ion-item,prop,button,boolean,false,false,false
ion-item,prop,color,string | undefined,undefined,false,true
ion-item,prop,color,string | undefined,undefined,false,false
ion-item,prop,detail,boolean | undefined,undefined,false,false
ion-item,prop,detailIcon,string,'chevron-forward',false,false
ion-item,prop,disabled,boolean,false,false,false
@@ -549,7 +549,7 @@ ion-item,part,detail-icon
ion-item,part,native
ion-item-divider,shadow
ion-item-divider,prop,color,string | undefined,undefined,false,true
ion-item-divider,prop,color,string | undefined,undefined,false,false
ion-item-divider,prop,mode,"ios" | "md",undefined,false,false
ion-item-divider,prop,sticky,boolean,false,false,false
ion-item-divider,css-prop,--background
@@ -566,7 +566,7 @@ ion-item-divider,css-prop,--padding-top
ion-item-group,none
ion-item-option,shadow
ion-item-option,prop,color,string | undefined,undefined,false,true
ion-item-option,prop,color,string | undefined,undefined,false,false
ion-item-option,prop,disabled,boolean,false,false,false
ion-item-option,prop,download,string | undefined,undefined,false,false
ion-item-option,prop,expandable,boolean,false,false,false
@@ -593,7 +593,7 @@ ion-item-sliding,method,open,open(side: Side | undefined) => Promise<void>
ion-item-sliding,event,ionDrag,any,true
ion-label,scoped
ion-label,prop,color,string | undefined,undefined,false,true
ion-label,prop,color,string | undefined,undefined,false,false
ion-label,prop,mode,"ios" | "md",undefined,false,false
ion-label,prop,position,"fixed" | "floating" | "stacked" | undefined,undefined,false,false
ion-label,css-prop,--color
@@ -605,7 +605,7 @@ ion-list,prop,mode,"ios" | "md",undefined,false,false
ion-list,method,closeSlidingItems,closeSlidingItems() => Promise<boolean>
ion-list-header,shadow
ion-list-header,prop,color,string | undefined,undefined,false,true
ion-list-header,prop,color,string | undefined,undefined,false,false
ion-list-header,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
ion-list-header,prop,mode,"ios" | "md",undefined,false,false
ion-list-header,css-prop,--background
@@ -676,7 +676,7 @@ ion-menu,part,container
ion-menu-button,shadow
ion-menu-button,prop,autoHide,boolean,true,false,false
ion-menu-button,prop,color,string | undefined,undefined,false,true
ion-menu-button,prop,color,string | undefined,undefined,false,false
ion-menu-button,prop,disabled,boolean,false,false,false
ion-menu-button,prop,menu,string | undefined,undefined,false,false
ion-menu-button,prop,mode,"ios" | "md",undefined,false,false
@@ -764,7 +764,7 @@ ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | und
ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-note,shadow
ion-note,prop,color,string | undefined,undefined,false,true
ion-note,prop,color,string | undefined,undefined,false,false
ion-note,prop,mode,"ios" | "md",undefined,false,false
ion-note,css-prop,--color
@@ -836,7 +836,7 @@ ion-popover,css-prop,--width
ion-progress-bar,shadow
ion-progress-bar,prop,buffer,number,1,false,false
ion-progress-bar,prop,color,string | undefined,undefined,false,true
ion-progress-bar,prop,color,string | undefined,undefined,false,false
ion-progress-bar,prop,mode,"ios" | "md",undefined,false,false
ion-progress-bar,prop,reversed,boolean,false,false,false
ion-progress-bar,prop,type,"determinate" | "indeterminate",'determinate',false,false
@@ -844,12 +844,9 @@ ion-progress-bar,prop,value,number,0,false,false
ion-progress-bar,css-prop,--background
ion-progress-bar,css-prop,--buffer-background
ion-progress-bar,css-prop,--progress-background
ion-progress-bar,part,progress
ion-progress-bar,part,stream
ion-progress-bar,part,track
ion-radio,shadow
ion-radio,prop,color,string | undefined,undefined,false,true
ion-radio,prop,color,string | undefined,undefined,false,false
ion-radio,prop,disabled,boolean,false,false,false
ion-radio,prop,mode,"ios" | "md",undefined,false,false
ion-radio,prop,name,string,this.inputId,false,false
@@ -867,10 +864,10 @@ ion-radio-group,none
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
ion-radio-group,prop,name,string,this.inputId,false,false
ion-radio-group,prop,value,any,undefined,false,false
ion-radio-group,event,ionChange,RadioGroupChangeEventDetail<any>,true
ion-radio-group,event,ionChange,RadioGroupChangeEventDetail,true
ion-range,shadow
ion-range,prop,color,string | undefined,undefined,false,true
ion-range,prop,color,string | undefined,undefined,false,false
ion-range,prop,debounce,number,0,false,false
ion-range,prop,disabled,boolean,false,false,false
ion-range,prop,dualKnobs,boolean,false,false,false
@@ -937,8 +934,8 @@ ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false,false
ion-ripple-effect,method,addRipple,addRipple(x: number, y: number) => Promise<() => void>
ion-route,none
ion-route,prop,beforeEnter,(() => NavigationHookResult | Promise<NavigationHookResult>) | undefined,undefined,false,false
ion-route,prop,beforeLeave,(() => NavigationHookResult | Promise<NavigationHookResult>) | undefined,undefined,false,false
ion-route,prop,beforeEnter,(() => boolean | NavigationHookOptions | Promise<NavigationHookResult>) | undefined,undefined,false,false
ion-route,prop,beforeLeave,(() => boolean | NavigationHookOptions | Promise<NavigationHookResult>) | undefined,undefined,false,false
ion-route,prop,component,string,undefined,true,false
ion-route,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
ion-route,prop,url,string,'',false,false
@@ -958,7 +955,7 @@ ion-router,event,ionRouteDidChange,RouterEventDetail,true
ion-router,event,ionRouteWillChange,RouterEventDetail,true
ion-router-link,shadow
ion-router-link,prop,color,string | undefined,undefined,false,true
ion-router-link,prop,color,string | undefined,undefined,false,false
ion-router-link,prop,href,string | undefined,undefined,false,false
ion-router-link,prop,rel,string | undefined,undefined,false,false
ion-router-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
@@ -981,7 +978,7 @@ ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', 'arrow-back-sharp') as string,false,false
ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false
ion-searchbar,prop,clearIcon,string | undefined,undefined,false,false
ion-searchbar,prop,color,string | undefined,undefined,false,true
ion-searchbar,prop,color,string | undefined,undefined,false,false
ion-searchbar,prop,debounce,number,250,false,false
ion-searchbar,prop,disabled,boolean,false,false,false
ion-searchbar,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
@@ -990,7 +987,6 @@ ion-searchbar,prop,mode,"ios" | "md",undefined,false,false
ion-searchbar,prop,placeholder,string,'Search',false,false
ion-searchbar,prop,searchIcon,string | undefined,undefined,false,false
ion-searchbar,prop,showCancelButton,"always" | "focus" | "never",'never',false,false
ion-searchbar,prop,showClearButton,"always" | "focus" | "never",'focus',false,false
ion-searchbar,prop,spellcheck,boolean,false,false,false
ion-searchbar,prop,type,"email" | "number" | "password" | "search" | "tel" | "text" | "url",'search',false,false
ion-searchbar,prop,value,null | string | undefined,'',false,false
@@ -1015,7 +1011,7 @@ ion-searchbar,css-prop,--placeholder-font-weight
ion-searchbar,css-prop,--placeholder-opacity
ion-segment,shadow
ion-segment,prop,color,string | undefined,undefined,false,true
ion-segment,prop,color,string | undefined,undefined,false,false
ion-segment,prop,disabled,boolean,false,false,false
ion-segment,prop,mode,"ios" | "md",undefined,false,false
ion-segment,prop,scrollable,boolean,false,false,false
@@ -1147,7 +1143,7 @@ ion-slides,css-prop,--scroll-bar-background
ion-slides,css-prop,--scroll-bar-background-active
ion-spinner,shadow
ion-spinner,prop,color,string | undefined,undefined,false,true
ion-spinner,prop,color,string | undefined,undefined,false,false
ion-spinner,prop,duration,number | undefined,undefined,false,false
ion-spinner,prop,name,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-small" | undefined,undefined,false,false
ion-spinner,prop,paused,boolean,false,false,false
@@ -1169,7 +1165,7 @@ ion-tab,prop,tab,string,undefined,true,false
ion-tab,method,setActive,setActive() => Promise<void>
ion-tab-bar,shadow
ion-tab-bar,prop,color,string | undefined,undefined,false,true
ion-tab-bar,prop,color,string | undefined,undefined,false,false
ion-tab-bar,prop,mode,"ios" | "md",undefined,false,false
ion-tab-bar,prop,selectedTab,string | undefined,undefined,false,false
ion-tab-bar,prop,translucent,boolean,false,false,false
@@ -1208,7 +1204,7 @@ ion-tabs,event,ionTabsDidChange,{ tab: string; },false
ion-tabs,event,ionTabsWillChange,{ tab: string; },false
ion-text,shadow
ion-text,prop,color,string | undefined,undefined,false,true
ion-text,prop,color,string | undefined,undefined,false,false
ion-text,prop,mode,"ios" | "md",undefined,false,false
ion-textarea,scoped
@@ -1216,7 +1212,7 @@ ion-textarea,prop,autoGrow,boolean,false,false,false
ion-textarea,prop,autocapitalize,string,'none',false,false
ion-textarea,prop,autofocus,boolean,false,false,false
ion-textarea,prop,clearOnEdit,boolean,false,false,false
ion-textarea,prop,color,string | undefined,undefined,false,true
ion-textarea,prop,color,string | undefined,undefined,false,false
ion-textarea,prop,cols,number | undefined,undefined,false,false
ion-textarea,prop,debounce,number,0,false,false
ion-textarea,prop,disabled,boolean,false,false,false
@@ -1256,14 +1252,14 @@ ion-thumbnail,css-prop,--border-radius
ion-thumbnail,css-prop,--size
ion-title,shadow
ion-title,prop,color,string | undefined,undefined,false,true
ion-title,prop,color,string | undefined,undefined,false,false
ion-title,prop,size,"large" | "small" | undefined,undefined,false,false
ion-title,css-prop,--color
ion-toast,shadow
ion-toast,prop,animated,boolean,true,false,false
ion-toast,prop,buttons,(string | ToastButton)[] | undefined,undefined,false,false
ion-toast,prop,color,string | undefined,undefined,false,true
ion-toast,prop,color,string | undefined,undefined,false,false
ion-toast,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-toast,prop,duration,number,0,false,false
ion-toast,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
@@ -1306,7 +1302,7 @@ ion-toast,part,message
ion-toggle,shadow
ion-toggle,prop,checked,boolean,false,false,false
ion-toggle,prop,color,string | undefined,undefined,false,true
ion-toggle,prop,color,string | undefined,undefined,false,false
ion-toggle,prop,disabled,boolean,false,false,false
ion-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-toggle,prop,name,string,this.inputId,false,false
@@ -1330,7 +1326,7 @@ ion-toggle,part,handle
ion-toggle,part,track
ion-toolbar,shadow
ion-toolbar,prop,color,string | undefined,undefined,false,true
ion-toolbar,prop,color,string | undefined,undefined,false,false
ion-toolbar,prop,mode,"ios" | "md",undefined,false,false
ion-toolbar,css-prop,--background
ion-toolbar,css-prop,--border-color

12949
core/package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "5.7.0",
"version": "5.5.5",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -24,38 +24,34 @@
"collection": "dist/collection/collection-manifest.json",
"types": "dist/types/interface.d.ts",
"files": [
"components/",
"css/",
"dist/",
"css/",
"hydrate/",
"loader/"
],
"dependencies": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
"ionicons": "^5.1.2",
"tslib": "^1.10.0"
},
"devDependencies": {
"@axe-core/puppeteer": "^4.1.1",
"@jest/core": "^26.6.3",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/core": "2.1.2",
"@stencil/sass": "1.3.2",
"@stencil/vue-output-target": "^0.4.3",
"@types/jest": "^26.0.20",
"@stencil/vue-output-target": "^0.4.1",
"@types/jest": "^26.0.10",
"@types/node": "^14.6.0",
"@types/puppeteer": "5.4.3",
"@types/puppeteer": "3.0.1",
"@types/swiper": "5.4.0",
"aws-sdk": "^2.738.0",
"clean-css-cli": "^4.1.11",
"domino": "^2.1.6",
"execa": "^5.0.0",
"fs-extra": "^9.0.1",
"jest": "^26.4.1",
"jest-cli": "^26.4.1",
"np": "^6.4.0",
"pixelmatch": "4.0.2",
"puppeteer": "^7.0.1",
"puppeteer": "^5.2.1",
"rollup": "^2.26.4",
"sass": "^1.26.10",
"stylelint": "^13.6.1",
@@ -67,7 +63,8 @@
"typescript": "^4.0.5"
},
"scripts": {
"build": "npm run clean && npm run build.css && stencil build --docs --es5 --docs-json dist/docs.json && npm run cdnloader",
"build": "npm run clean && npm run build.css && npm run build.vendor && stencil build --docs --es5 --docs-json dist/docs.json && npm run cdnloader",
"build.vendor": "rollup --config ./scripts/swiper.rollup.config.js",
"build.css": "npm run css.sass && npm run css.minify",
"build.debug": "npm run clean && stencil build --debug",
"build.docs": "stencil build --docs",

View File

@@ -1,2 +0,0 @@
export * from './index';
export * from '../dist/types/interface';

View File

@@ -1,9 +0,0 @@
{
"name": "@ionic/core/components",
"version": "0.0.0",
"description": "Ionic Components exported as custom elements, extending HTMLElement.",
"main": "./index.js",
"types": "./custom-elements.d.ts",
"private": true,
"sideEffects": false
}

View File

@@ -13,7 +13,7 @@ const s3 = new S3({ apiVersion: '2006-03-01' });
class CIScreenshotConnector extends IonicConnector {
async initBuild(opts) {
const { stdout: result } = await execa('git', ['log', '-1', '--format=%H%n%an <%ae>%n%ct%n%s']);
const result = await execa.stdout('git', ['log', '-1', '--format=%H%n%an <%ae>%n%ct%n%s']);
const [ sha1, author, timestamp, msg ] = result.split('\n');
const sha1short = sha1.slice(0, 7);
@@ -125,6 +125,8 @@ class CIScreenshotConnector extends IonicConnector {
uploadPaths.push(path.join(appRoot, 'scripts', 'testing', 'styles.css'));
const distDir = path.join(appRoot, 'dist');
uploadPaths.push(path.join(distDir, 'ionic.js'));
const distIonicDir = path.join(distDir, 'ionic');
fs.readdirSync(distIonicDir).forEach(distIonicFile => {
uploadPaths.push(path.join(distIonicDir, distIonicFile));

View File

@@ -0,0 +1,12 @@
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/components/slides/swiper/swiper.js',
output: {
file: 'src/components/slides/swiper/swiper.bundle.js',
format: 'es'
},
plugins: [
resolve()
]
};

View File

@@ -4,15 +4,15 @@ const virtual = require('@rollup/plugin-virtual');
const fs = require('fs');
async function main() {
const input = process.argv[2] || getMainEntry();
const result = await check(input);
const relative = path.relative(process.cwd(), input);
const input = process.argv[2] || getInput();
const result = await check(input);
const relative = path.relative(process.cwd(), input);
if (result.shaken) {
console.error(`Success! ${relative} is fully tree-shakeable`);
} else {
error(`Failed to tree-shake ${relative}`);
};
if (result.shaken) {
console.error(`Success! ${relative} is fully tree-shakeable`);
} else {
error(`Failed to tree-shake ${relative}`);
}
}
function error(msg) {
@@ -20,10 +20,10 @@ function error(msg) {
process.exit(1);
}
function getMainEntry() {
if (!fs.existsSync('package.json')) {
error(`Could not find package.json`);
}
function getInput() {
if (!fs.existsSync('package.json')) {
error(`Could not find package.json`);
}
const pkg = JSON.parse(fs.readFileSync('package.json'), 'utf-8');
@@ -38,20 +38,20 @@ function getMainEntry() {
}
function resolve(file) {
if (isDirectory(file)) {
return ifExists(`${file}/index.cjs.js`) || ifExists(`${file}/index.js`);
}
if (isDirectory(file)) {
return ifExists(`${file}/index.js`) || ifExists(`${file}/index.cjs.js`);
}
return ifExists(file) || ifExists(`${file}.cjs.js`) || ifExists(`${file}.js`);
return ifExists(file) || ifExists(`${file}.js`) || ifExists(`${file}.cjs.js`);
}
function isDirectory(file) {
try {
const stats = fs.statSync(file);
return stats.isDirectory();
} catch (err) {
return false;
}
try {
const stats = fs.statSync(file);
return stats.isDirectory();
} catch (err) {
return false;
}
}
function ifExists(file) {
@@ -67,7 +67,7 @@ async function check(input) {
virtual({
__agadoo__: `import ${JSON.stringify(resolved)}`,
tslib: `
const noop = () => {};
const noop = () => {};
export const __awaiter = noop;
export const __extends = noop;
export const __generator = noop;

View File

@@ -1225,7 +1225,7 @@ export namespace Components {
*/
"close": (animated?: boolean) => Promise<boolean>;
/**
* The `id` of the main content. When using a router this is typically `ion-router-outlet`. When not using a router, this is typically your main view's `ion-content`. This is not the id of the `ion-content` inside of your `ion-menu`.
* The content's id the menu should use.
*/
"contentId"?: string;
/**
@@ -1914,7 +1914,7 @@ export namespace Components {
*/
"root": string;
/**
* The router can work in two "modes": - With hash: `/index.html#/path/to/page` - Without hash: `/path/to/page` Using one or another might depend in the requirements of your app and/or where it's deployed. Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might requires additional server-side configuration in order to properly work. On the other side hash-navigation is much easier to deploy, it even works over the file protocol. By default, this property is `true`, change to `false` to allow hash-less URLs.
* The router can work in two "modes": - With hash: `/index.html#/path/to/page` - Without hash: `/path/to/page` Using one or another might depend in the requirements of your app and/or where it's deployed. Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might requires additional server-side configuration in order to properly work. On the otherside hash-navigation is much easier to deploy, it even works over the file protocol. By default, this property is `true`, change to `false` to allow hash-less URLs.
*/
"useHash": boolean;
}
@@ -2034,10 +2034,6 @@ export namespace Components {
* Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state.
*/
"showCancelButton": 'never' | 'focus' | 'always';
/**
* Sets the behavior for the clear button. Defaults to `"focus"`. Setting to `"focus"` shows the clear button on focus if the input is not empty. Setting to `"never"` hides the clear button. Setting to `"always"` shows the clear button regardless of focus state, but only if the input is not empty.
*/
"showClearButton": 'never' | 'focus' | 'always';
/**
* If `true`, enable spellcheck on the input.
*/
@@ -2303,7 +2299,7 @@ export namespace Components {
}
interface IonSplitPane {
/**
* The `id` of the main content. When using a router this is typically `ion-router-outlet`. When not using a router, this is typically your main view's `ion-content`. This is not the id of the `ion-content` inside of your `ion-menu`.
* The content `id` of the split-pane's main content.
*/
"contentId"?: string;
/**
@@ -4568,7 +4564,7 @@ declare namespace LocalJSX {
}
interface IonMenu {
/**
* The `id` of the main content. When using a router this is typically `ion-router-outlet`. When not using a router, this is typically your main view's `ion-content`. This is not the id of the `ion-content` inside of your `ion-menu`.
* The content's id the menu should use.
*/
"contentId"?: string;
/**
@@ -5200,7 +5196,7 @@ declare namespace LocalJSX {
*/
"root"?: string;
/**
* The router can work in two "modes": - With hash: `/index.html#/path/to/page` - Without hash: `/path/to/page` Using one or another might depend in the requirements of your app and/or where it's deployed. Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might requires additional server-side configuration in order to properly work. On the other side hash-navigation is much easier to deploy, it even works over the file protocol. By default, this property is `true`, change to `false` to allow hash-less URLs.
* The router can work in two "modes": - With hash: `/index.html#/path/to/page` - Without hash: `/path/to/page` Using one or another might depend in the requirements of your app and/or where it's deployed. Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might requires additional server-side configuration in order to properly work. On the otherside hash-navigation is much easier to deploy, it even works over the file protocol. By default, this property is `true`, change to `false` to allow hash-less URLs.
*/
"useHash"?: boolean;
}
@@ -5340,10 +5336,6 @@ declare namespace LocalJSX {
* Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state.
*/
"showCancelButton"?: 'never' | 'focus' | 'always';
/**
* Sets the behavior for the clear button. Defaults to `"focus"`. Setting to `"focus"` shows the clear button on focus if the input is not empty. Setting to `"never"` hides the clear button. Setting to `"always"` shows the clear button regardless of focus state, but only if the input is not empty.
*/
"showClearButton"?: 'never' | 'focus' | 'always';
/**
* If `true`, enable spellcheck on the input.
*/
@@ -5625,7 +5617,7 @@ declare namespace LocalJSX {
}
interface IonSplitPane {
/**
* The `id` of the main content. When using a router this is typically `ion-router-outlet`. When not using a router, this is typically your main view's `ion-content`. This is not the id of the `ion-content` inside of your `ion-menu`.
* The content `id` of the split-pane's main content.
*/
"contentId"?: string;
/**

View File

@@ -110,16 +110,10 @@
text-align: $action-sheet-ios-text-align;
}
.action-sheet-title.action-sheet-has-sub-title {
font-weight: $action-sheet-ios-title-with-sub-title-font-weight;
}
.action-sheet-sub-title {
@include padding($action-sheet-ios-sub-title-padding-top, $action-sheet-ios-sub-title-padding-end, $action-sheet-ios-sub-title-padding-bottom, $action-sheet-ios-sub-title-padding-start);
font-size: $action-sheet-ios-sub-title-font-size;
font-weight: $action-sheet-ios-title-font-weight;
}

View File

@@ -55,9 +55,6 @@ $action-sheet-ios-title-font-size: 13px !default;
/// @prop - Font weight of the action sheet title
$action-sheet-ios-title-font-weight: 400 !default;
/// @prop - Font weight of the action sheet title when it has a sub title
$action-sheet-ios-title-with-sub-title-font-weight: 600 !default;
/// @prop - Border width of the action sheet title
$action-sheet-ios-title-border-width: $hairlines-width !default;
@@ -75,10 +72,10 @@ $action-sheet-ios-title-border-color: rgba($text-col
// --------------------------------------------------
/// @prop - Font size of the action sheet sub title
$action-sheet-ios-sub-title-font-size: 13px !default;
$action-sheet-ios-sub-title-font-size: 12px !default;
/// @prop - Padding top of the action sheet sub title
$action-sheet-ios-sub-title-padding-top: 6px !default;
$action-sheet-ios-sub-title-padding-top: 15px !default;
/// @prop - Padding end of the action sheet sub title
$action-sheet-ios-sub-title-padding-end: 0 !default;
@@ -106,7 +103,7 @@ $action-sheet-ios-button-text-color: ion-color(prim
$action-sheet-ios-button-icon-font-size: 28px !default;
/// @prop - Padding right of the action sheet button icon
$action-sheet-ios-button-icon-padding-right: .3em !default;
$action-sheet-ios-button-icon-padding-right: .1em !default;
/// @prop - Font size of the action sheet button
$action-sheet-ios-button-font-size: 20px !default;

View File

@@ -23,7 +23,7 @@
.action-sheet-title {
@include padding($action-sheet-md-title-padding-top, $action-sheet-md-title-padding-end, $action-sheet-md-title-padding-bottom, $action-sheet-md-title-padding-start);
min-height: $action-sheet-md-title-height;
height: $action-sheet-md-title-height;
color: var(--color, $action-sheet-md-title-color);

View File

@@ -258,10 +258,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
<div class="action-sheet-container">
<div class="action-sheet-group" ref={el => this.groupEl = el}>
{this.header !== undefined &&
<div class={{
'action-sheet-title': true,
'action-sheet-has-sub-title': this.subHeader !== undefined
}}>
<div class="action-sheet-title">
{this.header}
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
</div>

View File

@@ -34,39 +34,6 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### ActionSheetButton
```typescript
interface ActionSheetButton {
text?: string;
role?: 'cancel' | 'destructive' | 'selected' | string;
icon?: string;
cssClass?: string | string[];
handler?: () => boolean | void | Promise<boolean | void>;
}
```
### ActionSheetOptions
```typescript
interface ActionSheetOptions {
header?: string;
subHeader?: string;
cssClass?: string | string[];
buttons: (ActionSheetButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
<!-- Auto Generated Below -->
@@ -127,9 +94,6 @@ export class ActionSheetExample {
}]
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
}
@@ -183,10 +147,7 @@ async function presentActionSheet() {
}
}];
document.body.appendChild(actionSheet);
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return actionSheet.present();
}
```
@@ -194,59 +155,6 @@ async function presentActionSheet() {
### React
```tsx
/* Using with useIonActionSheet Hook */
import React from 'react';
import {
IonButton,
IonContent,
IonPage,
useIonActionSheet,
} from '@ionic/react';
const ActionSheetExample: React.FC = () => {
const [present, dismiss] = useIonActionSheet();
return (
<IonPage>
<IonContent>
<IonButton
expand="block"
onClick={() =>
present({
buttons: [{ text: 'Ok' }, { text: 'Cancel' }],
header: 'Action Sheet'
})
}
>
Show ActionSheet
</IonButton>
<IonButton
expand="block"
onClick={() =>
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet')
}
>
Show ActionSheet using params
</IonButton>
<IonButton
expand="block"
onClick={() => {
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet');
setTimeout(dismiss, 3000);
}}
>
Show ActionSheet, hide after 3 seconds
</IonButton>
</IonContent>
</IonPage>
);
};
```
```tsx
/* Using with IonActionSheet Component */
import React, { useState } from 'react';
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';
@@ -355,9 +263,6 @@ export class ActionSheetExample {
}]
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
render() {
@@ -431,10 +336,7 @@ export default defineComponent({
},
],
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return actionSheet.present();
},
},
});
@@ -451,7 +353,7 @@ Developers can also use this component directly in their template:
header="Albums"
css-class="my-custom-class"
:buttons="buttons"
@didDismiss="setOpen(false)"
@onDidDismiss="setOpen(false)"
>
</ion-action-sheet>
</template>

View File

@@ -70,7 +70,6 @@
const mode = Ionic.mode;
await openActionSheet({
header: "Albums",
subHeader: 'This is a sub header inside of an action sheet',
buttons: [{
text: 'Delete',
role: 'destructive',

View File

@@ -71,7 +71,7 @@ export const testActionSheetAlert = async (
const alert = await page.find('ion-alert');
await alert.waitForVisible();
await page.waitForTimeout(250);
await page.waitFor(250);
screenshotCompares.push(await page.compareScreenshot(`alert open`));

View File

@@ -50,9 +50,6 @@ export class ActionSheetExample {
}]
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
}

View File

@@ -38,9 +38,6 @@ async function presentActionSheet() {
}
}];
document.body.appendChild(actionSheet);
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return actionSheet.present();
}
```

View File

@@ -1,57 +1,4 @@
```tsx
/* Using with useIonActionSheet Hook */
import React from 'react';
import {
IonButton,
IonContent,
IonPage,
useIonActionSheet,
} from '@ionic/react';
const ActionSheetExample: React.FC = () => {
const [present, dismiss] = useIonActionSheet();
return (
<IonPage>
<IonContent>
<IonButton
expand="block"
onClick={() =>
present({
buttons: [{ text: 'Ok' }, { text: 'Cancel' }],
header: 'Action Sheet'
})
}
>
Show ActionSheet
</IonButton>
<IonButton
expand="block"
onClick={() =>
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet')
}
>
Show ActionSheet using params
</IonButton>
<IonButton
expand="block"
onClick={() => {
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet');
setTimeout(dismiss, 3000);
}}
>
Show ActionSheet, hide after 3 seconds
</IonButton>
</IonContent>
</IonPage>
);
};
```
```tsx
/* Using with IonActionSheet Component */
import React, { useState } from 'react';
import { IonActionSheet, IonContent, IonButton } from '@ionic/react';
import { trash, share, caretForwardCircle, heart, close } from 'ionicons/icons';

View File

@@ -47,9 +47,6 @@ export class ActionSheetExample {
}]
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
render() {

View File

@@ -56,10 +56,7 @@ export default defineComponent({
},
],
});
await actionSheet.present();
const { role } = await actionSheet.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return actionSheet.present();
},
},
});
@@ -76,7 +73,7 @@ Developers can also use this component directly in their template:
header="Albums"
css-class="my-custom-class"
:buttons="buttons"
@didDismiss="setOpen(false)"
@onDidDismiss="setOpen(false)"
>
</ion-action-sheet>
</template>

View File

@@ -44,7 +44,7 @@ export interface AlertInputAttributes extends JSXBase.InputHTMLAttributes<HTMLIn
export interface AlertButton {
text: string;
role?: 'cancel' | 'destructive' | string;
role?: string;
cssClass?: string | string[];
handler?: (value: any) => boolean | void | {[key: string]: any};
}

View File

@@ -41,76 +41,6 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### AlertButton
```typescript
interface AlertButton {
text: string;
role?: 'cancel' | 'destructive' | string;
cssClass?: string | string[];
handler?: (value: any) => boolean | void | {[key: string]: any};
}
```
### AlertInput
```typescript
interface AlertInput {
type?: TextFieldTypes | 'checkbox' | 'radio' | 'textarea';
name?: string;
placeholder?: string;
value?: any;
label?: string;
checked?: boolean;
disabled?: boolean;
id?: string;
handler?: (input: AlertInput) => void;
min?: string | number;
max?: string | number;
cssClass?: string | string[];
attributes?: AlertInputAttributes | AlertTextareaAttributes;
tabindex?: number;
}
```
### AlertInputAttributes
```typescript
interface AlertInputAttributes extends JSXBase.InputHTMLAttributes<HTMLInputElement> {}
```
### AlertOptions
```typescript
interface AlertOptions {
header?: string;
subHeader?: string;
message?: string | IonicSafeString;
cssClass?: string | string[];
inputs?: AlertInput[];
buttons?: (AlertButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### AlertTextareaAttributes
```typescript
interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement> {}
```
<!-- Auto Generated Below -->
@@ -142,9 +72,6 @@ export class AlertExample {
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
async presentAlertMultipleButtons() {
@@ -277,55 +204,37 @@ export class AlertExample {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -358,9 +267,6 @@ export class AlertExample {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
@@ -368,50 +274,35 @@ export class AlertExample {
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -454,10 +345,7 @@ function presentAlert() {
alert.buttons = ['OK'];
document.body.appendChild(alert);
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return alert.present();
}
function presentAlertMultipleButtons() {
@@ -586,50 +474,32 @@ function presentAlertRadio() {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
];
alert.buttons = [
@@ -660,55 +530,37 @@ function presentAlertCheckbox() {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
];
alert.buttons = [
@@ -736,48 +588,6 @@ function presentAlertCheckbox() {
### React
```tsx
/* Using with useIonAlert Hook */
import React from 'react';
import { IonButton, IonContent, IonPage, useIonAlert } from '@ionic/react';
const AlertExample: React.FC = () => {
const [present] = useIonAlert();
return (
<IonPage>
<IonContent fullscreen>
<IonButton
expand="block"
onClick={() =>
present({
cssClass: 'my-css',
header: 'Alert',
message: 'alert from hook',
buttons: [
'Cancel',
{ text: 'Ok', handler: (d) => console.log('ok pressed') },
],
onDidDismiss: (e) => console.log('did dismiss'),
})
}
>
Show Alert
</IonButton>
<IonButton
expand="block"
onClick={() => present('hello with params', [{ text: 'Ok' }])}
>
Show Alert using params
</IonButton>
</IonContent>
</IonPage>
);
};
```
```tsx
/* Using with IonAlert Component */
import React, { useState } from 'react';
import { IonAlert, IonButton, IonContent } from '@ionic/react';
@@ -928,55 +738,37 @@ export const AlertExample: React.FC = () => {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
]}
buttons={[
@@ -1008,55 +800,37 @@ export const AlertExample: React.FC = () => {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
]}
buttons={[
@@ -1107,9 +881,6 @@ export class AlertExample {
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
async presentAlertMultipleButtons() {
@@ -1242,55 +1013,37 @@ export class AlertExample {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -1323,59 +1076,42 @@ export class AlertExample {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -1443,10 +1179,7 @@ export default defineComponent({
message: 'This is an alert message.',
buttons: ['OK'],
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return alert.present();
},
async presentAlertMultipleButtons() {
@@ -1571,50 +1304,32 @@ export default defineComponent({
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true,
},
{
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
},
{
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
},
{
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
},
{
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
},
{
type: 'radio',
label: 'Radio 6',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
},
],
buttons: [
@@ -1647,9 +1362,6 @@ export default defineComponent({
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true,
},
@@ -1657,45 +1369,30 @@ export default defineComponent({
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
},
],
buttons: [
@@ -1734,7 +1431,7 @@ Developers can also use this component directly in their template:
message="This is an alert message."
css-class="my-custom-class"
:buttons="buttons"
@didDismiss="setOpen(false)"
@onDidDismiss="setOpen(false)"
>
</ion-alert>
</template>

View File

@@ -21,9 +21,6 @@ export class AlertExample {
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
async presentAlertMultipleButtons() {
@@ -156,55 +153,37 @@ export class AlertExample {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -237,9 +216,6 @@ export class AlertExample {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
@@ -247,50 +223,35 @@ export class AlertExample {
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
],
buttons: [

View File

@@ -8,10 +8,7 @@ function presentAlert() {
alert.buttons = ['OK'];
document.body.appendChild(alert);
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return alert.present();
}
function presentAlertMultipleButtons() {
@@ -140,50 +137,32 @@ function presentAlertRadio() {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
];
alert.buttons = [
@@ -214,55 +193,37 @@ function presentAlertCheckbox() {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
];
alert.buttons = [

View File

@@ -1,46 +1,4 @@
```tsx
/* Using with useIonAlert Hook */
import React from 'react';
import { IonButton, IonContent, IonPage, useIonAlert } from '@ionic/react';
const AlertExample: React.FC = () => {
const [present] = useIonAlert();
return (
<IonPage>
<IonContent fullscreen>
<IonButton
expand="block"
onClick={() =>
present({
cssClass: 'my-css',
header: 'Alert',
message: 'alert from hook',
buttons: [
'Cancel',
{ text: 'Ok', handler: (d) => console.log('ok pressed') },
],
onDidDismiss: (e) => console.log('did dismiss'),
})
}
>
Show Alert
</IonButton>
<IonButton
expand="block"
onClick={() => present('hello with params', [{ text: 'Ok' }])}
>
Show Alert using params
</IonButton>
</IonContent>
</IonPage>
);
};
```
```tsx
/* Using with IonAlert Component */
import React, { useState } from 'react';
import { IonAlert, IonButton, IonContent } from '@ionic/react';
@@ -191,55 +149,37 @@ export const AlertExample: React.FC = () => {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
]}
buttons={[
@@ -271,55 +211,37 @@ export const AlertExample: React.FC = () => {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
]}
buttons={[

View File

@@ -18,9 +18,6 @@ export class AlertExample {
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
}
async presentAlertMultipleButtons() {
@@ -153,55 +150,37 @@ export class AlertExample {
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true
},
{
name: 'radio2',
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
value: 'value2'
},
{
name: 'radio3',
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
value: 'value3'
},
{
name: 'radio4',
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
value: 'value4'
},
{
name: 'radio5',
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
value: 'value5'
},
{
name: 'radio6',
type: 'radio',
label: 'Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 Radio 6 ',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
value: 'value6'
}
],
buttons: [
@@ -234,59 +213,42 @@ export class AlertExample {
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true
},
{
name: 'checkbox2',
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
value: 'value2'
},
{
name: 'checkbox3',
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
value: 'value3'
},
{
name: 'checkbox4',
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
value: 'value4'
},
{
name: 'checkbox5',
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
value: 'value5'
},
{
name: 'checkbox6',
type: 'checkbox',
label: 'Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6 Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
value: 'value6'
}
],
buttons: [

View File

@@ -24,10 +24,7 @@ export default defineComponent({
message: 'This is an alert message.',
buttons: ['OK'],
});
await alert.present();
const { role } = await alert.onDidDismiss();
console.log('onDidDismiss resolved with role', role);
return alert.present();
},
async presentAlertMultipleButtons() {
@@ -152,50 +149,32 @@ export default defineComponent({
type: 'radio',
label: 'Radio 1',
value: 'value1',
handler: () => {
console.log('Radio 1 selected');
},
checked: true,
},
{
type: 'radio',
label: 'Radio 2',
value: 'value2',
handler: () => {
console.log('Radio 2 selected');
}
},
{
type: 'radio',
label: 'Radio 3',
value: 'value3',
handler: () => {
console.log('Radio 3 selected');
}
},
{
type: 'radio',
label: 'Radio 4',
value: 'value4',
handler: () => {
console.log('Radio 4 selected');
}
},
{
type: 'radio',
label: 'Radio 5',
value: 'value5',
handler: () => {
console.log('Radio 5 selected');
}
},
{
type: 'radio',
label: 'Radio 6',
value: 'value6',
handler: () => {
console.log('Radio 6 selected');
}
},
],
buttons: [
@@ -228,9 +207,6 @@ export default defineComponent({
type: 'checkbox',
label: 'Checkbox 1',
value: 'value1',
handler: () => {
console.log('Checkbox 1 selected');
},
checked: true,
},
@@ -238,45 +214,30 @@ export default defineComponent({
type: 'checkbox',
label: 'Checkbox 2',
value: 'value2',
handler: () => {
console.log('Checkbox 2 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 3',
value: 'value3',
handler: () => {
console.log('Checkbox 3 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 4',
value: 'value4',
handler: () => {
console.log('Checkbox 4 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 5',
value: 'value5',
handler: () => {
console.log('Checkbox 5 selected');
}
},
{
type: 'checkbox',
label: 'Checkbox 6',
value: 'value6',
handler: () => {
console.log('Checkbox 6 selected');
}
},
],
buttons: [
@@ -315,7 +276,7 @@ Developers can also use this component directly in their template:
message="This is an alert message."
css-class="my-custom-class"
:buttons="buttons"
@didDismiss="setOpen(false)"
@onDidDismiss="setOpen(false)"
>
</ion-alert>
</template>

View File

@@ -92,13 +92,6 @@
font-kerning: none;
}
// Back Button Ripple effect
// --------------------------------------------------
ion-ripple-effect {
color: var(--ripple-color);
}
// Back Button with Color
// --------------------------------------------------
@@ -248,4 +241,4 @@ ion-icon {
:host(.in-toolbar:not(.in-toolbar-color)) {
color: #{var(--ion-toolbar-color, var(--color))};
}
}

View File

@@ -30,7 +30,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
@Prop({ reflect: true }) color?: Color;
@Prop() color?: Color;
/**
* The url to navigate back to by default when there is no history.

Some files were not shown because too many files have changed in this diff Show More