mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38e97bc0b3 | ||
|
|
0989ea5ac8 | ||
|
|
69928924f7 | ||
|
|
5ffacb1875 | ||
|
|
fe99fbf5e8 | ||
|
|
3a4555c5a9 | ||
|
|
e17e6cdd08 | ||
|
|
5c15ed5161 | ||
|
|
f0cebfb617 | ||
|
|
265f6d6e6c | ||
|
|
33247065a6 | ||
|
|
8cbde1a3df |
@@ -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
|
||||
@@ -197,7 +185,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install
|
||||
command: npm install --legacy-peer-deps
|
||||
working_directory: /tmp/workspace/packages/vue
|
||||
- run:
|
||||
command: sudo npm link
|
||||
@@ -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
|
||||
@@ -222,7 +208,13 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install
|
||||
command: npm install --legacy-peer-deps
|
||||
working_directory: /tmp/workspace/packages/vue-router
|
||||
- run:
|
||||
command: sudo npm link
|
||||
working_directory: /tmp/workspace/core
|
||||
- run:
|
||||
command: sudo npm link @ionic/core
|
||||
working_directory: /tmp/workspace/packages/vue-router
|
||||
- run:
|
||||
command: sudo npm link
|
||||
@@ -236,7 +228,7 @@ jobs:
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- packages/vue-router/dist
|
||||
- "*"
|
||||
|
||||
test-core-clean-build:
|
||||
<<: *defaults
|
||||
@@ -399,33 +391,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,49 +423,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:
|
||||
<<: *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
|
||||
|
||||
test-vue-e2e:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm run sync
|
||||
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:
|
||||
@@ -517,11 +442,8 @@ workflows:
|
||||
requires: [puppeteer-dependencies, build-core]
|
||||
- test-core-spec:
|
||||
requires: [build-core]
|
||||
# Adam requested we skip this test for now
|
||||
# since it is failing on ES5 code which
|
||||
# will be removed in Ionic Framework v6
|
||||
#- test-core-treeshake:
|
||||
# requires: [build-core]
|
||||
- test-core-treeshake:
|
||||
requires: [build-core]
|
||||
- test-core-screenshot:
|
||||
requires: [build-core]
|
||||
filters:
|
||||
@@ -549,26 +471,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:
|
||||
requires: [install-vue-test-app, build-vue, build-vue-router]
|
||||
- test-vue-e2e:
|
||||
requires: [install-vue-test-app, build-vue, build-vue-router]
|
||||
- test-angular-lint:
|
||||
requires: [build-angular]
|
||||
- test-angular-e2e:
|
||||
|
||||
262
.github/COMPONENT-GUIDE.md
vendored
262
.github/COMPONENT-GUIDE.md
vendored
@@ -9,9 +9,6 @@
|
||||
* [Ripple Effect](#ripple-effect)
|
||||
* [Example Components](#example-components)
|
||||
* [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)
|
||||
@@ -365,265 +362,6 @@ ion-ripple-effect {
|
||||
- [iOS Buttons](https://developer.apple.com/design/human-interface-guidelines/ios/controls/buttons/)
|
||||
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Checkbox
|
||||
|
||||
#### Example Components
|
||||
|
||||
- [ion-checkbox](https://github.com/ionic-team/ionic/tree/master/core/src/components/checkbox)
|
||||
|
||||
#### VoiceOver
|
||||
|
||||
In order for VoiceOver to work properly with a checkbox component there must be a native `input` with `type="checkbox"`, and `aria-checked` and `role="checkbox"` **must** be on the host element. The `aria-hidden` attribute needs to be added if the checkbox 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="checkbox"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
/>
|
||||
...
|
||||
</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="checkbox"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
aria-checked={`${checked}`}
|
||||
disabled={disabled}
|
||||
/>
|
||||
...
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Labels
|
||||
|
||||
A helper function has been created to get the proper `aria-label` for the checkbox. 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 Checkbox implements ComponentInterface {
|
||||
private inputId = `ion-cb-${checkboxIds++}`;
|
||||
|
||||
@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="checkbox"
|
||||
>
|
||||
```
|
||||
|
||||
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="checkbox"
|
||||
>
|
||||
<label htmlFor={inputId}>
|
||||
{labelText}
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
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 checkbox to work with forms.
|
||||
|
||||
#### Known Issues
|
||||
|
||||
When using VoiceOver on macOS, Chrome will announce the following when you are focused on a checkbox:
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
10
.github/PROCESS.md
vendored
10
.github/PROCESS.md
vendored
@@ -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
|
||||
|
||||
|
||||
5
.github/ionic-issue-bot.yml
vendored
5
.github/ionic-issue-bot.yml
vendored
@@ -27,10 +27,7 @@ comment:
|
||||
is added to issues that need a code reproduction.
|
||||
|
||||
|
||||
Please reproduce this issue in an Ionic starter application and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.
|
||||
|
||||
|
||||
If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for our team to reproduce the issue.
|
||||
Please provide a reproduction with the minimum amount of code required to reproduce the issue. Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.
|
||||
|
||||
|
||||
For a guide on how to create a good reproduction, see our [Contributing Guide](https://ionicframework.com/docs/contributing/how-to-contribute#creating-a-good-code-reproduction).
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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/
|
||||
|
||||
@@ -63,9 +63,8 @@ async function main() {
|
||||
function checkProductionRelease() {
|
||||
const corePath = common.projectPath('core');
|
||||
const hasEsm = fs.existsSync(path.join(corePath, 'dist', 'esm'));
|
||||
const hasEsmEs5 = fs.existsSync(path.join(corePath, 'dist', 'esm-es5'));
|
||||
const hasCjs = fs.existsSync(path.join(corePath, 'dist', 'cjs'));
|
||||
if (!hasEsm || !hasEsmEs5 || !hasCjs) {
|
||||
if (!hasEsm || !hasCjs) {
|
||||
throw new Error('core build is not a production build');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
230
CHANGELOG.md
230
CHANGELOG.md
@@ -1,233 +1,3 @@
|
||||
## [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vue:** account for event name changes in vue 3.0.6+ ([#22980](https://github.com/ionic-team/ionic/issues/22980)) ([7dd2e6d](https://github.com/ionic-team/ionic/commit/7dd2e6d287b47cca758e1d4a71928dd3dc9ac24d)), closes [#22977](https://github.com/ionic-team/ionic/issues/22977)
|
||||
|
||||
|
||||
|
||||
## [5.5.4](https://github.com/ionic-team/ionic/compare/v5.5.3...v5.5.4) (2021-02-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** update ngAdd schematic ([#22858](https://github.com/ionic-team/ionic/issues/22858)) ([487349f](https://github.com/ionic-team/ionic/commit/487349f02a41344db2478735d27bf79f2a1c99b3))
|
||||
* **app:** keyboard no longer hides when using contenteditable ([#22857](https://github.com/ionic-team/ionic/issues/22857)) ([b6b2d34](https://github.com/ionic-team/ionic/commit/b6b2d34fd446feb06cf0143946a014d19231a78e)), closes [#22856](https://github.com/ionic-team/ionic/issues/22856)
|
||||
* **ios**: scroll assist no longer prevents first click event from firing ([#22845](https://github.com/ionic-team/ionic/issues/22845)) ([f7d4c21](https://github.com/ionic-team/ionic/commit/f7d4c21b64e27f9b655bc1ab2522d6357dc6010f)), closes [#21871](https://github.com/ionic-team/ionic/issues/21871)
|
||||
* **select:** class on component now indicates when select is open ([#22846](https://github.com/ionic-team/ionic/issues/22846)) ([1a5accc](https://github.com/ionic-team/ionic/commit/1a5accc5f707f84063469c0bd3e5e153489f1e5d)), closes [#22801](https://github.com/ionic-team/ionic/issues/22801)
|
||||
* **vue:** ionChange events now propagate correctly ([#22872](https://github.com/ionic-team/ionic/issues/22872)) ([ff0f1da](https://github.com/ionic-team/ionic/commit/ff0f1da9f11915b48c4258af7c48c4513785f3fc)), closes [#22870](https://github.com/ionic-team/ionic/issues/22870)
|
||||
|
||||
|
||||
|
||||
## [5.5.3](https://github.com/ionic-team/ionic/compare/v5.5.2...v5.5.3) (2021-01-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **react:** do not unmount overlay inner component until overlay is dismissed ([#22813](https://github.com/ionic-team/ionic/issues/22813)) ([ab1fc8f](https://github.com/ionic-team/ionic/commit/ab1fc8f2311fd252146942c7a947ebc96efd054f)), closes [#22761](https://github.com/ionic-team/ionic/issues/22761)
|
||||
* **react:** adding dynamic class to ion-page no longer hides component ([#22666](https://github.com/ionic-team/ionic/issues/22666)) ([a01bdb8](https://github.com/ionic-team/ionic/commit/a01bdb8c8dfee760721eeb35a8b556954f3b5b13)), closes [#22631](https://github.com/ionic-team/ionic/issues/22631)
|
||||
* **react:** improve view matching logic ([#22569](https://github.com/ionic-team/ionic/issues/22569)) ([f891f66](https://github.com/ionic-team/ionic/commit/f891f667082d2deb5f1b5f0f27af46e46ed1ca0f))
|
||||
* **react, vue:** do not show back button when replacing to root page ([#22750](https://github.com/ionic-team/ionic/issues/22750)) ([9e9a372](https://github.com/ionic-team/ionic/commit/9e9a3724979e95f3df1a340be21d16d8664a013c)), closes [#22528](https://github.com/ionic-team/ionic/issues/22528)
|
||||
* **refresher:** correctly detect spinner when using native refresher ([#22800](https://github.com/ionic-team/ionic/issues/22800)) ([e2d8e5c](https://github.com/ionic-team/ionic/commit/e2d8e5c4dcf893ddd8aaa556c1dd8fcaf52411c9)), closes [#22706](https://github.com/ionic-team/ionic/issues/22706)
|
||||
* **title:** only add large title transition when using collapsible header ([#22762](https://github.com/ionic-team/ionic/issues/22762)) ([348c50b](https://github.com/ionic-team/ionic/commit/348c50b7ea5d4c74498c5d26e40c1c4fe923ee55)), closes [#22760](https://github.com/ionic-team/ionic/issues/22760)
|
||||
* **vue:** all ionic vue components can now use router link ([#22743](https://github.com/ionic-team/ionic/issues/22743)) ([3d6ac13](https://github.com/ionic-team/ionic/commit/3d6ac1382e23663a3d010fd253d3c6017d3923e4))
|
||||
* **vue:** correctly determine leaving view when transitioning to a new instance of a previous page ([#22655](https://github.com/ionic-team/ionic/issues/22655)) ([e3a05bf](https://github.com/ionic-team/ionic/commit/e3a05bfeb55d8eaa38aa08a37859aa4df6ffa2d4)), closes [#22654](https://github.com/ionic-team/ionic/issues/22654) [#22658](https://github.com/ionic-team/ionic/issues/22658)
|
||||
* **vue:** ensure v-model value is properly synced before ionChange event ([#22749](https://github.com/ionic-team/ionic/issues/22749)) ([e1d6627](https://github.com/ionic-team/ionic/commit/e1d6627bf0ef1f47f980db1573c6b2a3d16d7677)), closes [#22610](https://github.com/ionic-team/ionic/issues/22610)
|
||||
* **vue:** improve path matching with tabs, deprecated adding additional pages as children of tabs without a router outlet ([#22807](https://github.com/ionic-team/ionic/issues/22807)) ([2a3ce9a](https://github.com/ionic-team/ionic/commit/2a3ce9a74e85111a2f1f470b9d8bfe2cda793ca5)), closes [#22519](https://github.com/ionic-team/ionic/issues/22519)
|
||||
* **vue:** improve v-model binding sync between vue wrappers and web components ([#22745](https://github.com/ionic-team/ionic/issues/22745)) ([64719f4](https://github.com/ionic-team/ionic/commit/64719f49f979c0296a01827d3c02599a48ba93a6)), closes [#22731](https://github.com/ionic-team/ionic/issues/22731)
|
||||
* **vue:** output commonjs format for node environments ([#22766](https://github.com/ionic-team/ionic/issues/22766)) ([7ecae2e](https://github.com/ionic-team/ionic/commit/7ecae2e4cb5d0eebc6041a8a7a5acc156132c2e1))
|
||||
* **vue:** tab bar is now correctly hidden when keyboard is open ([#22687](https://github.com/ionic-team/ionic/issues/22687)) ([5c27dd8](https://github.com/ionic-team/ionic/commit/5c27dd8032d32ebb57c31e1f6c112dc513344b93))
|
||||
|
||||
|
||||
|
||||
## [5.5.2](https://github.com/ionic-team/ionic/compare/v5.5.1...v5.5.2) (2020-12-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **android:** setting hardwareBackButton: false in config now disables default webview behavior ([#22555](https://github.com/ionic-team/ionic/issues/22555)) ([dc9faa6](https://github.com/ionic-team/ionic/commit/dc9faa6a0fbebb64c83c107c79cfd486cc0c096a)), closes [#18237](https://github.com/ionic-team/ionic/issues/18237)
|
||||
* **button:** allow aria-label to be inherited on inner button ([#22632](https://github.com/ionic-team/ionic/issues/22632)) ([818e387](https://github.com/ionic-team/ionic/commit/818e387fe81ac7026fb374d8865116dadd433c87)), closes [#22629](https://github.com/ionic-team/ionic/issues/22629)
|
||||
* **react:** hardware back button now navigates correctly ([36939e1](https://github.com/ionic-team/ionic/commit/36939e10ae0b8ac9a9275ee06d8e0d345de7c64f))
|
||||
* **react:** setting a ref now allows other props to be passed in ([31f45cd](https://github.com/ionic-team/ionic/commit/31f45cdcc953b08749d9db08321fa5ec6cbe2532)), closes [#22609](https://github.com/ionic-team/ionic/issues/22609)
|
||||
* **refresher:** clean up old css if calling refresh method before native refresher is setup ([#22640](https://github.com/ionic-team/ionic/issues/22640)) ([8d5ed47](https://github.com/ionic-team/ionic/commit/8d5ed47a282f92a60a2c4126a673cc2a5733067e)), closes [#22636](https://github.com/ionic-team/ionic/issues/22636)
|
||||
* **refresher:** refresher correctly detects native refresher when shown asynchronously ([#22623](https://github.com/ionic-team/ionic/issues/22623)) ([5ed73cd](https://github.com/ionic-team/ionic/commit/5ed73cdf4d63eeee25ef28d9676fcaa4f8e07b47)), closes [#22616](https://github.com/ionic-team/ionic/issues/22616)
|
||||
* **vue:** adding non tab button elements inside ion-tab-bar no longer causes errors ([#22643](https://github.com/ionic-team/ionic/issues/22643)) ([61cf0c5](https://github.com/ionic-team/ionic/commit/61cf0c534e45ce09410be6bfb50bdc27b657d1bc)), closes [#22642](https://github.com/ionic-team/ionic/issues/22642)
|
||||
* **vue:** correctly handle navigation failures ([#22621](https://github.com/ionic-team/ionic/issues/22621)) ([216f51b](https://github.com/ionic-team/ionic/commit/216f51b12a8c4ae7b410f47ce3d350ea513b68a1)), closes [#22591](https://github.com/ionic-team/ionic/issues/22591)
|
||||
* **vue:** correctly remove old view when replacing route ([#22566](https://github.com/ionic-team/ionic/issues/22566)) ([4f4f31b](https://github.com/ionic-team/ionic/commit/4f4f31b65e48294c3130ff24ae00b1a2aa1f9d31)), closes [#22492](https://github.com/ionic-team/ionic/issues/22492)
|
||||
* **vue:** pass in correct route to props function ([#22605](https://github.com/ionic-team/ionic/issues/22605)) ([01afdc4](https://github.com/ionic-team/ionic/commit/01afdc42e5b1598d4d15cb51761bbb3eb5d13893)), closes [#22602](https://github.com/ionic-team/ionic/issues/22602)
|
||||
* **vue:** query strings are now correctly handled when navigating back ([#22615](https://github.com/ionic-team/ionic/issues/22615)) ([a94e2a8](https://github.com/ionic-team/ionic/commit/a94e2a87fb759e7b7daed2d0304c1199dbc7afd1)), closes [#22517](https://github.com/ionic-team/ionic/issues/22517)
|
||||
* **vue:** swipe back gesture is properly disabled when swipeBackEnabled config is false ([#22568](https://github.com/ionic-team/ionic/issues/22568)) ([9d04c12](https://github.com/ionic-team/ionic/commit/9d04c127e817676983940b034a4c7efc92fdfbc6)), closes [#22567](https://github.com/ionic-team/ionic/issues/22567)
|
||||
|
||||
### For Ionic Vue Developers
|
||||
|
||||
Vue Router 4 has been released! Be sure to update from the release candidate to the latest stable version of Vue Router.
|
||||
|
||||
For more information on the changes in Vue Router 4, see https://github.com/vuejs/vue-router-next/releases/tag/v4.0.0.
|
||||
|
||||
```
|
||||
npm install vue-router@4
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## [5.5.1](https://github.com/ionic-team/ionic/compare/v5.5.0...v5.5.1) (2020-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **checkbox:** click handler now fires properly ([#22573](https://github.com/ionic-team/ionic/issues/22573)) ([0786835](https://github.com/ionic-team/ionic/commit/07868354aaf88deebf7472a5bf0f34d7c823de17)), closes [#22557](https://github.com/ionic-team/ionic/issues/22557)
|
||||
* **radio:** properly announce radios on screen readers and resolve axe errors ([#22507](https://github.com/ionic-team/ionic/issues/22507)) ([afcc46e](https://github.com/ionic-team/ionic/commit/afcc46e1cc4d7f6e9d1a50f8b367da4b1d0c3143))
|
||||
* **react:** eliminate use of deprecated `findDOMNode`, resolves [#20972](https://github.com/ionic-team/ionic/issues/20972) ([5275332](https://github.com/ionic-team/ionic/commit/5275332e43694f3ee8738a1726c0d202b16c3052))
|
||||
* **router:** navigation guards now fire when navigating to a page with params ([#22521](https://github.com/ionic-team/ionic/issues/22521)) ([1956f98](https://github.com/ionic-team/ionic/commit/1956f9896883dc4687488e5418e50ce0f6cbe6c9)), closes [#22516](https://github.com/ionic-team/ionic/issues/22516)
|
||||
* **select:** fix a11y issues with axe and screen readers ([#22494](https://github.com/ionic-team/ionic/issues/22494)) ([04b874e](https://github.com/ionic-team/ionic/commit/04b874e32a65588ca79eda9399ab7e9d86a3cb77)), closes [#21552](https://github.com/ionic-team/ionic/issues/21552) [#21548](https://github.com/ionic-team/ionic/issues/21548)
|
||||
* **select:** improvements for announcing placeholder and value on screenreaders ([#22556](https://github.com/ionic-team/ionic/issues/22556)) ([ea52db6](https://github.com/ionic-team/ionic/commit/ea52db66f05a185fed6b2e849734a7ffa1c6c6ea))
|
||||
* **vue:** onBeforeRouteLeave and onBeforeRouteUpdate hooks now fire properly ([#22542](https://github.com/ionic-team/ionic/issues/22542)) ([8002114](https://github.com/ionic-team/ionic/commit/8002114e720361e60d7a7fe2d15ab88b49a72e1b)), closes [#22540](https://github.com/ionic-team/ionic/issues/22540)
|
||||
* **vue:** tabs now correctly fire lifecycle events ([#22479](https://github.com/ionic-team/ionic/issues/22479)) ([cdc2fb6](https://github.com/ionic-team/ionic/commit/cdc2fb652fe5aa149eaa751a77fb506ac1f64195)), closes [#22466](https://github.com/ionic-team/ionic/issues/22466)
|
||||
* **vue:** unit testing a routerLink-capable component no longer warns of missing router dependency ([#22532](https://github.com/ionic-team/ionic/issues/22532)) ([4e23aad](https://github.com/ionic-team/ionic/commit/4e23aad3d911188e4a2706545463a81332c00ce9)), closes [#22506](https://github.com/ionic-team/ionic/issues/22506)
|
||||
|
||||
### For Ionic Vue Developers
|
||||
|
||||
When updating to Ionic Vue v5.5.1 make sure you are on the latest version of `vue-router@next` to take advantage of the bug fixes in this release:
|
||||
|
||||
```
|
||||
npm install vue-router@next
|
||||
```
|
||||
|
||||
|
||||
|
||||
# [5.5.0 Chlorine](https://github.com/ionic-team/ionic/compare/v5.4.4...v5.5.0) (2020-11-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **backdrop:** nvda no longer incorrectly announces backdrop ([#22481](https://github.com/ionic-team/ionic/issues/22481)) ([2d878fc](https://github.com/ionic-team/ionic/commit/2d878fc4f6c7a710dbfb722e188e3e402e1672f9)), closes [#22102](https://github.com/ionic-team/ionic/issues/22102)
|
||||
* **checkbox:** use a native input to fix a11y issues with axe and screen readers ([#22402](https://github.com/ionic-team/ionic/issues/22402)) ([7214a84](https://github.com/ionic-team/ionic/commit/7214a8401b709e1353155304cf6e9f97b2b4d294)), closes [#21644](https://github.com/ionic-team/ionic/issues/21644) [#20517](https://github.com/ionic-team/ionic/issues/20517) [#17796](https://github.com/ionic-team/ionic/issues/17796)
|
||||
* **input:** title attribute is now automatically inherited ([#22493](https://github.com/ionic-team/ionic/issues/22493)) ([abad12f](https://github.com/ionic-team/ionic/commit/abad12fbdb1378066282fe8e9b7761747951b685)), closes [#22055](https://github.com/ionic-team/ionic/issues/22055)
|
||||
* **refresher:** ios native refresher now works in side menu ([#22449](https://github.com/ionic-team/ionic/issues/22449)) ([a4a6453](https://github.com/ionic-team/ionic/commit/a4a64530ff083b83187b293dfdacb0fa45ad9f51))
|
||||
* **refresher:** md native refresher now works in side menu ([#22446](https://github.com/ionic-team/ionic/issues/22446)) ([6b817f2](https://github.com/ionic-team/ionic/commit/6b817f26b08d01d8367d16308db775b6192e7628)), closes [#20832](https://github.com/ionic-team/ionic/issues/20832)
|
||||
* **toggle:** use a native input to fix a11y issues with axe and screen readers ([#22477](https://github.com/ionic-team/ionic/issues/22477)) ([813611a](https://github.com/ionic-team/ionic/commit/813611a61b664c9827760ccaa889d0e2fcae7d94)), closes [#22011](https://github.com/ionic-team/ionic/issues/22011) [#21552](https://github.com/ionic-team/ionic/issues/21552)
|
||||
* **vue:** correctly pass route props to components ([#22476](https://github.com/ionic-team/ionic/issues/22476)) ([0956f8b](https://github.com/ionic-team/ionic/commit/0956f8bc5588836996c8c74f98166c347414a312)), closes [#22472](https://github.com/ionic-team/ionic/issues/22472)
|
||||
* **vue:** tab bar now works with slot="top" ([#22461](https://github.com/ionic-team/ionic/issues/22461)) ([e17c822](https://github.com/ionic-team/ionic/commit/e17c822bfbc2a876226738b77a4c95c02e0b5953)), closes [#22456](https://github.com/ionic-team/ionic/issues/22456)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **chip:** add disabled property ([#20658](https://github.com/ionic-team/ionic/issues/20658)) ([0a0cbd8](https://github.com/ionic-team/ionic/commit/0a0cbd8f2a505ad2b3d8afb60cb1e940ced52e0d)), closes [#19510](https://github.com/ionic-team/ionic/issues/19510)
|
||||
* **segment:** add swipeGesture property to allow for disabling of the swipe gesture ([#22087](https://github.com/ionic-team/ionic/issues/22087)) ([65bc995](https://github.com/ionic-team/ionic/commit/65bc99577c44cce653dafd9937c4d8f9c45fff61)), closes [#22048](https://github.com/ionic-team/ionic/issues/22048)
|
||||
* **vue:** composition api lifecycle methods ([#22241](https://github.com/ionic-team/ionic/issues/22241)) ([f5b0299](https://github.com/ionic-team/ionic/commit/f5b0299729c2c639e432612e62fb7eaa189ca969))
|
||||
* **vue:** vetur support ([#22403](https://github.com/ionic-team/ionic/issues/22403)) ([e76f79d](https://github.com/ionic-team/ionic/commit/e76f79d0548c97edd193808f5e0a19889cffae5b))
|
||||
* **vue:** web-types support ([#22428](https://github.com/ionic-team/ionic/issues/22428)) ([639314a](https://github.com/ionic-team/ionic/commit/639314ab218b65a9a2de6040417b0e1b363e47ef)), closes [#19522](https://github.com/ionic-team/ionic/issues/19522)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ios:** move content to stacking context while preserving position: fixed behavior ([#22489](https://github.com/ionic-team/ionic/issues/22489)) ([d77a9d5](https://github.com/ionic-team/ionic/commit/d77a9d57ec02c69df43ec2a286eea674a85cae36)), closes [#22473](https://github.com/ionic-team/ionic/issues/22473)
|
||||
|
||||
|
||||
|
||||
## [5.4.4](https://github.com/ionic-team/ionic/compare/v5.4.3...v5.4.4) (2020-11-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** add missing es5 output ([228d349](https://github.com/ionic-team/ionic/commit/228d349c6e29b62cbfee5d5502883682cfa5032f))
|
||||
|
||||
|
||||
|
||||
## [5.4.3](https://github.com/ionic-team/ionic/compare/v5.4.2...v5.4.3) (2020-11-06)
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
145
angular/package-lock.json
generated
145
angular/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "5.6.5",
|
||||
"version": "5.4.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "5.6.5",
|
||||
"version": "5.4.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "5.6.4",
|
||||
"@ionic/core": "file:../core",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -42,6 +42,43 @@
|
||||
"zone.js": ">=0.8.26"
|
||||
}
|
||||
},
|
||||
"../core": {
|
||||
"version": "5.4.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ionicons": "^5.1.2",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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.1.8",
|
||||
"@types/jest": "^26.0.10",
|
||||
"@types/node": "^14.6.0",
|
||||
"@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",
|
||||
"fs-extra": "^9.0.1",
|
||||
"jest": "^26.4.1",
|
||||
"jest-cli": "^26.4.1",
|
||||
"np": "^6.4.0",
|
||||
"pixelmatch": "4.0.2",
|
||||
"puppeteer": "^5.2.1",
|
||||
"rollup": "^2.26.4",
|
||||
"sass": "^1.26.10",
|
||||
"stylelint": "^13.6.1",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"swiper": "5.4.1",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
"tslint-react": "^5.0.0",
|
||||
"typescript": "^4.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/core": {
|
||||
"version": "8.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.17.tgz",
|
||||
@@ -204,19 +241,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.4.tgz",
|
||||
"integrity": "sha512-fxCV/+0ibiaiBn1dsrrOmlLGJlTkqiG6IVXdLpPKimGdFLjy56olDvB5trlz9J5C/nHc7vR5MIiYC0qdTyX7og==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^2.4.0",
|
||||
"ionicons": "^5.5.1",
|
||||
"tslib": "^2.1.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=="
|
||||
"resolved": "../core",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs": {
|
||||
"version": "11.1.0",
|
||||
@@ -296,18 +322,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.5.0.tgz",
|
||||
"integrity": "sha512-gpoYJEYzu5LV2hr7uPZklug3zXhEbYGKyNodPfmOOYZtO9q42l7RQ3cAnC8MzEoF4jFrfemgtevGik8sqn9ClQ==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.10.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
|
||||
@@ -931,6 +945,7 @@
|
||||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.1",
|
||||
"braces": "^2.3.2",
|
||||
"fsevents": "^1.2.7",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.3",
|
||||
"is-binary-path": "^1.0.0",
|
||||
@@ -2032,14 +2047,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ionicons": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
|
||||
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-accessor-descriptor": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
|
||||
@@ -2422,7 +2429,13 @@
|
||||
"integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"errno": "^0.1.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"image-size": "~0.5.0",
|
||||
"make-dir": "^2.1.0",
|
||||
"mime": "^1.4.1",
|
||||
"native-request": "^1.0.5",
|
||||
"source-map": "~0.6.0",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -2805,6 +2818,7 @@
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
@@ -2945,6 +2959,9 @@
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.7.5.tgz",
|
||||
"integrity": "sha512-xQSM8uzhgtF6tTnTVEvOQThrcG3LPUP3T/4l4EukzDp0kbTY1QRDuXjiwtYzs9odKj9Bj/PccRG6viFfS7DmCQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fsevents": "~2.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
@@ -5156,20 +5173,37 @@
|
||||
}
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.4.tgz",
|
||||
"integrity": "sha512-fxCV/+0ibiaiBn1dsrrOmlLGJlTkqiG6IVXdLpPKimGdFLjy56olDvB5trlz9J5C/nHc7vR5MIiYC0qdTyX7og==",
|
||||
"version": "file:../core",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.4.0",
|
||||
"ionicons": "^5.5.1",
|
||||
"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=="
|
||||
}
|
||||
"@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.1.8",
|
||||
"@types/jest": "^26.0.10",
|
||||
"@types/node": "^14.6.0",
|
||||
"@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",
|
||||
"fs-extra": "^9.0.1",
|
||||
"ionicons": "^5.1.2",
|
||||
"jest": "^26.4.1",
|
||||
"jest-cli": "^26.4.1",
|
||||
"np": "^6.4.0",
|
||||
"pixelmatch": "4.0.2",
|
||||
"puppeteer": "^5.2.1",
|
||||
"rollup": "^2.26.4",
|
||||
"sass": "^1.26.10",
|
||||
"stylelint": "^13.6.1",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"swiper": "5.4.1",
|
||||
"tslib": "^1.10.0",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
"tslint-react": "^5.0.0",
|
||||
"typescript": "^4.0.5"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-commonjs": {
|
||||
@@ -5242,11 +5276,6 @@
|
||||
"integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.5.0.tgz",
|
||||
"integrity": "sha512-gpoYJEYzu5LV2hr7uPZklug3zXhEbYGKyNodPfmOOYZtO9q42l7RQ3cAnC8MzEoF4jFrfemgtevGik8sqn9ClQ=="
|
||||
},
|
||||
"@szmarczak/http-timer": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
|
||||
@@ -6661,14 +6690,6 @@
|
||||
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
|
||||
"dev": true
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
|
||||
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
|
||||
"requires": {
|
||||
"@stencil/core": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"is-accessor-descriptor": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "5.6.5",
|
||||
"version": "5.4.3",
|
||||
"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.6.5",
|
||||
"@ionic/core": "5.4.3",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ export class IonCheckbox {
|
||||
}
|
||||
export declare interface IonChip extends Components.IonChip {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["color", "disabled", "mode", "outline"] })
|
||||
@Component({ selector: "ion-chip", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "disabled", "mode", "outline"] })
|
||||
@ProxyCmp({ inputs: ["color", "mode", "outline"] })
|
||||
@Component({ selector: "ion-chip", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "mode", "outline"] })
|
||||
export class IonChip {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
@@ -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>;
|
||||
@@ -661,8 +661,8 @@ export class IonSearchbar {
|
||||
}
|
||||
export declare interface IonSegment extends Components.IonSegment {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["color", "disabled", "mode", "scrollable", "swipeGesture", "value"] })
|
||||
@Component({ selector: "ion-segment", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "disabled", "mode", "scrollable", "swipeGesture", "value"] })
|
||||
@ProxyCmp({ inputs: ["color", "disabled", "mode", "scrollable", "value"] })
|
||||
@Component({ selector: "ion-segment", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "disabled", "mode", "scrollable", "value"] })
|
||||
export class IonSegment {
|
||||
ionChange!: EventEmitter<CustomEvent>;
|
||||
protected el: HTMLElement;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -40,23 +40,20 @@ function addIonicAngularModuleToAppModule(projectSourceRoot: Path): Rule {
|
||||
function addIonicStyles(projectName: string, projectSourceRoot: Path): Rule {
|
||||
return (host: Tree) => {
|
||||
const ionicStyles = [
|
||||
'node_modules/@ionic/angular/css/core.css',
|
||||
'node_modules/@ionic/angular/css/normalize.css',
|
||||
'node_modules/@ionic/angular/css/structure.css',
|
||||
'node_modules/@ionic/angular/css/typography.css',
|
||||
'node_modules/@ionic/angular/css/display.css',
|
||||
'node_modules/@ionic/angular/css/core.css',
|
||||
'node_modules/@ionic/angular/css/padding.css',
|
||||
'node_modules/@ionic/angular/css/float-elements.css',
|
||||
'node_modules/@ionic/angular/css/text-alignment.css',
|
||||
'node_modules/@ionic/angular/css/text-transformation.css',
|
||||
'node_modules/@ionic/angular/css/flex-utils.css',
|
||||
`${projectSourceRoot}/theme/variables.css`
|
||||
]
|
||||
|
||||
ionicStyles.forEach(entry => {
|
||||
].forEach(entry => {
|
||||
addStyle(host, projectName, entry);
|
||||
});
|
||||
return host;
|
||||
return host;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,8 +64,7 @@ function addIonicons(projectName: string): Rule {
|
||||
input: 'node_modules/ionicons/dist/ionicons/svg',
|
||||
output: './svg'
|
||||
};
|
||||
addAsset(host, projectName, 'build', ioniconsGlob);
|
||||
addAsset(host, projectName, 'test', ioniconsGlob);
|
||||
addAsset(host, projectName, ioniconsGlob);
|
||||
return host;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,10 +62,10 @@ export function addStyle(host: Tree, projectName: string, stylePath: string) {
|
||||
writeConfig(host, config);
|
||||
}
|
||||
|
||||
export function addAsset(host: Tree, projectName: string, architect: string, asset: string | {glob: string; input: string; output: string}) {
|
||||
export function addAsset(host: Tree, projectName: string, asset: string | {glob: string; input: string; output: string}) {
|
||||
const config = readConfig(host);
|
||||
const appConfig = getAngularAppConfig(config, projectName);
|
||||
appConfig.architect[architect].options.assets.push(asset);
|
||||
appConfig.architect.build.options.assets.push(asset);
|
||||
writeConfig(host, config);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ export interface IonicWindow extends Window {
|
||||
}
|
||||
|
||||
export interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady?(): Promise<this>;
|
||||
forceUpdate?(): void;
|
||||
componentOnReady(): Promise<this>;
|
||||
forceUpdate(): void;
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"integrationFolder": "./e2e",
|
||||
"testFiles": "**/*.spec.ts",
|
||||
"baseUrl": "http://localhost:4200/",
|
||||
"ignoreTestFiles": "**/examples/*",
|
||||
"video": false,
|
||||
"screenshotOnRunFailure": false
|
||||
}
|
||||
22
angular/test/test-app/cypress/plugins/index.js
vendored
22
angular/test/test-app/cypress/plugins/index.js
vendored
@@ -1,22 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
||||
@@ -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')
|
||||
});
|
||||
69
angular/test/test-app/cypress/support/index.d.ts
vendored
69
angular/test/test-app/cypress/support/index.d.ts
vendored
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
20
angular/test/test-app/cypress/support/index.js
vendored
20
angular/test/test-app/cypress/support/index.js
vendored
@@ -1,20 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
14
angular/test/test-app/e2e/protractor-ci.conf.js
Normal file
14
angular/test/test-app/e2e/protractor-ci.conf.js
Normal 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;
|
||||
35
angular/test/test-app/e2e/protractor.conf.js
Normal file
35
angular/test/test-app/e2e/protractor.conf.js
Normal 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 } }));
|
||||
}
|
||||
};
|
||||
133
angular/test/test-app/e2e/src/form.e2e-spec.ts
Normal file
133
angular/test/test-app/e2e/src/form.e2e-spec.ts
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
})
|
||||
}
|
||||
69
angular/test/test-app/e2e/src/inputs.e2e-spec.ts
Normal file
69
angular/test/test-app/e2e/src/inputs.e2e-spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
})
|
||||
55
angular/test/test-app/e2e/src/modal.e2e-spec.ts
Normal file
55
angular/test/test-app/e2e/src/modal.e2e-spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
});
|
||||
73
angular/test/test-app/e2e/src/navigation.e2e-spec.ts
Normal file
73
angular/test/test-app/e2e/src/navigation.e2e-spec.ts
Normal 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();
|
||||
}
|
||||
@@ -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');
|
||||
});
|
||||
})
|
||||
|
||||
23
angular/test/test-app/e2e/src/nested-outlet.e2e-spec.ts
Normal file
23
angular/test/test-app/e2e/src/nested-outlet.e2e-spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
29
angular/test/test-app/e2e/src/providers.e2e-spec.ts
Normal file
29
angular/test/test-app/e2e/src/providers.e2e-spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
194
angular/test/test-app/e2e/src/router-link.e2e-spec.ts
Normal file
194
angular/test/test-app/e2e/src/router-link.e2e-spec.ts
Normal 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,
|
||||
});
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
@@ -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');
|
||||
});
|
||||
})
|
||||
51
angular/test/test-app/e2e/src/slides.e2e-spec.ts
Normal file
51
angular/test/test-app/e2e/src/slides.e2e-spec.ts
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
334
angular/test/test-app/e2e/src/tabs.e2e-spec.ts
Normal file
334
angular/test/test-app/e2e/src/tabs.e2e-spec.ts
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
73
angular/test/test-app/e2e/src/utils.ts
Normal file
73
angular/test/test-app/e2e/src/utils.ts
Normal 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);
|
||||
}
|
||||
22
angular/test/test-app/e2e/src/view-child.e2e-spec.ts
Normal file
22
angular/test/test-app/e2e/src/view-child.e2e-spec.ts
Normal 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');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
18
angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
Normal file
18
angular/test/test-app/e2e/src/virtual-scroll.e2e-spec.ts
Normal 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);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
38
angular/test/test-app/karma.conf.js
Normal file
38
angular/test/test-app/karma.conf.js
Normal 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
|
||||
});
|
||||
};
|
||||
20065
angular/test/test-app/package-lock.json
generated
20065
angular/test/test-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,16 +8,15 @@
|
||||
"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 85.0.4183.87",
|
||||
"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": "^9.1.12",
|
||||
@@ -35,6 +34,7 @@
|
||||
"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": "^1.13.0",
|
||||
"zone.js": "^0.10.3"
|
||||
@@ -46,15 +46,22 @@
|
||||
"@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": "^5.2.2",
|
||||
"concurrently": "^6.0.0",
|
||||
"cypress": "^6.7.1",
|
||||
"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.3",
|
||||
"typescript": "^3.8.3",
|
||||
"wait-on": "^5.2.1",
|
||||
"webpack-cli": "^3.3.12"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
20
angular/test/test-app/src/test.ts
Normal file
20
angular/test/test-app/src/test.ts
Normal 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);
|
||||
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
12
core/api.txt
12
core/api.txt
@@ -248,7 +248,6 @@ ion-checkbox,part,mark
|
||||
|
||||
ion-chip,shadow
|
||||
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
|
||||
ion-chip,css-prop,--background
|
||||
@@ -333,7 +332,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
|
||||
@@ -844,9 +843,6 @@ 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,false
|
||||
@@ -937,8 +933,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
|
||||
@@ -990,7 +986,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
|
||||
@@ -1019,7 +1014,6 @@ 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
|
||||
ion-segment,prop,swipeGesture,boolean,true,false,false
|
||||
ion-segment,prop,value,null | string | undefined,undefined,false,false
|
||||
ion-segment,event,ionChange,SegmentChangeEventDetail,true
|
||||
ion-segment,css-prop,--background
|
||||
|
||||
12944
core/package-lock.json
generated
12944
core/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "5.6.5",
|
||||
"version": "5.4.3",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -24,27 +24,24 @@
|
||||
"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.1",
|
||||
"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.2",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@stencil/vue-output-target": "0.1.8",
|
||||
"@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",
|
||||
@@ -54,7 +51,7 @@
|
||||
"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",
|
||||
@@ -78,7 +75,7 @@
|
||||
"css.sass": "sass src/css:./css",
|
||||
"lint": "npm run lint.ts && npm run lint.sass",
|
||||
"lint.fix": "npm run lint.ts.fix && npm run lint.sass.fix",
|
||||
"lint.sass": "stylelint \"src/**/*.scss\"",
|
||||
"lint.sass": "stylelint 'src/**/*.scss'",
|
||||
"lint.sass.fix": "npm run lint.sass -- --fix",
|
||||
"lint.ts": "tslint --project .",
|
||||
"lint.ts.fix": "tslint --project . --fix",
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './index';
|
||||
export * from '../dist/types/interface';
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
46
core/src/components.d.ts
vendored
46
core/src/components.d.ts
vendored
@@ -394,7 +394,7 @@ export namespace Components {
|
||||
*/
|
||||
"name": string;
|
||||
/**
|
||||
* The value of the checkbox does not mean if it's checked or not, use the `checked` property for that. The value of a checkbox is analogous to the value of an `<input type="checkbox">`, it's only used when the checkbox participates in a native `<form>`.
|
||||
* The value of the toggle does not mean if it's checked or not, use the `checked` property for that. The value of a toggle is analogous to the value of a `<input type="checkbox">`, it's only used when the toggle participates in a native `<form>`.
|
||||
*/
|
||||
"value": string;
|
||||
}
|
||||
@@ -403,10 +403,6 @@ export namespace Components {
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@@ -834,7 +830,7 @@ export namespace Components {
|
||||
*/
|
||||
"accept"?: string;
|
||||
/**
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
||||
*/
|
||||
"autocapitalize": string;
|
||||
/**
|
||||
@@ -1225,7 +1221,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;
|
||||
/**
|
||||
@@ -1708,7 +1704,7 @@ export namespace Components {
|
||||
*/
|
||||
"name": string;
|
||||
"setButtonTabindex": (value: number) => Promise<void>;
|
||||
"setFocus": (ev: any) => Promise<void>;
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
* the value of the radio.
|
||||
*/
|
||||
@@ -2034,10 +2030,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.
|
||||
*/
|
||||
@@ -2068,10 +2060,6 @@ export namespace Components {
|
||||
* If `true`, the segment buttons will overflow and the user can swipe to see them. In addition, this will disable the gesture to drag the indicator between the buttons in order to swipe to see hidden buttons.
|
||||
*/
|
||||
"scrollable": boolean;
|
||||
/**
|
||||
* If `true`, users will be able to swipe between segment buttons to activate them.
|
||||
*/
|
||||
"swipeGesture": boolean;
|
||||
/**
|
||||
* the value of the segment.
|
||||
*/
|
||||
@@ -2303,7 +2291,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;
|
||||
/**
|
||||
@@ -3713,7 +3701,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"name"?: string;
|
||||
/**
|
||||
* Emitted when the checkbox loses focus.
|
||||
* Emitted when the toggle loses focus.
|
||||
*/
|
||||
"onIonBlur"?: (event: CustomEvent<void>) => void;
|
||||
/**
|
||||
@@ -3721,7 +3709,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"onIonChange"?: (event: CustomEvent<CheckboxChangeEventDetail>) => void;
|
||||
/**
|
||||
* Emitted when the checkbox has focus.
|
||||
* Emitted when the toggle has focus.
|
||||
*/
|
||||
"onIonFocus"?: (event: CustomEvent<void>) => void;
|
||||
/**
|
||||
@@ -3729,7 +3717,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"onIonStyle"?: (event: CustomEvent<StyleEventDetail>) => void;
|
||||
/**
|
||||
* The value of the checkbox does not mean if it's checked or not, use the `checked` property for that. The value of a checkbox is analogous to the value of an `<input type="checkbox">`, it's only used when the checkbox participates in a native `<form>`.
|
||||
* The value of the toggle does not mean if it's checked or not, use the `checked` property for that. The value of a toggle is analogous to the value of a `<input type="checkbox">`, it's only used when the toggle participates in a native `<form>`.
|
||||
*/
|
||||
"value"?: string;
|
||||
}
|
||||
@@ -3738,10 +3726,6 @@ declare namespace LocalJSX {
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
@@ -4185,7 +4169,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"accept"?: string;
|
||||
/**
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
||||
*/
|
||||
"autocapitalize"?: string;
|
||||
/**
|
||||
@@ -4568,7 +4552,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;
|
||||
/**
|
||||
@@ -5340,10 +5324,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.
|
||||
*/
|
||||
@@ -5386,10 +5366,6 @@ declare namespace LocalJSX {
|
||||
* If `true`, the segment buttons will overflow and the user can swipe to see them. In addition, this will disable the gesture to drag the indicator between the buttons in order to swipe to see hidden buttons.
|
||||
*/
|
||||
"scrollable"?: boolean;
|
||||
/**
|
||||
* If `true`, users will be able to swipe between segment buttons to activate them.
|
||||
*/
|
||||
"swipeGesture"?: boolean;
|
||||
/**
|
||||
* the value of the segment.
|
||||
*/
|
||||
@@ -5625,7 +5601,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;
|
||||
/**
|
||||
|
||||
@@ -94,9 +94,6 @@ export class ActionSheetExample {
|
||||
}]
|
||||
});
|
||||
await actionSheet.present();
|
||||
|
||||
const { role } = await actionSheet.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -150,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();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -161,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';
|
||||
@@ -322,9 +263,6 @@ export class ActionSheetExample {
|
||||
}]
|
||||
});
|
||||
await actionSheet.present();
|
||||
|
||||
const { role } = await actionSheet.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -398,10 +336,7 @@ export default defineComponent({
|
||||
},
|
||||
],
|
||||
});
|
||||
await actionSheet.present();
|
||||
|
||||
const { role } = await actionSheet.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
return actionSheet.present();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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`));
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@ export class ActionSheetExample {
|
||||
}]
|
||||
});
|
||||
await actionSheet.present();
|
||||
|
||||
const { role } = await actionSheet.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -47,9 +47,6 @@ export class ActionSheetExample {
|
||||
}]
|
||||
});
|
||||
await actionSheet.present();
|
||||
|
||||
const { role } = await actionSheet.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -158,7 +158,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
|
||||
// If hitting arrow down or arrow right, move to the next radio
|
||||
// If we're on the last radio, move to the first radio
|
||||
if (['ArrowDown', 'ArrowRight'].includes(ev.code)) {
|
||||
if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
|
||||
nextEl = (index === radios.length - 1)
|
||||
? radios[0]
|
||||
: radios[index + 1];
|
||||
@@ -166,7 +166,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
|
||||
// If hitting arrow up or arrow left, move to the previous radio
|
||||
// If we're on the first radio, move to the last radio
|
||||
if (['ArrowUp', 'ArrowLeft'].includes(ev.code)) {
|
||||
if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
|
||||
nextEl = (index === 0)
|
||||
? radios[radios.length - 1]
|
||||
: radios[index - 1];
|
||||
@@ -373,24 +373,22 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
return values;
|
||||
}
|
||||
|
||||
private renderAlertInputs() {
|
||||
private renderAlertInputs(labelledBy: string | undefined) {
|
||||
switch (this.inputType) {
|
||||
case 'checkbox': return this.renderCheckbox();
|
||||
case 'radio': return this.renderRadio();
|
||||
default: return this.renderInput();
|
||||
case 'checkbox': return this.renderCheckbox(labelledBy);
|
||||
case 'radio': return this.renderRadio(labelledBy);
|
||||
default: return this.renderInput(labelledBy);
|
||||
}
|
||||
}
|
||||
|
||||
private renderCheckbox() {
|
||||
private renderCheckbox(labelledby: string | undefined) {
|
||||
const inputs = this.processedInputs;
|
||||
const mode = getIonMode(this);
|
||||
|
||||
if (inputs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="alert-checkbox-group">
|
||||
<div class="alert-checkbox-group" aria-labelledby={labelledby}>
|
||||
{ inputs.map(i => (
|
||||
<button
|
||||
type="button"
|
||||
@@ -424,15 +422,13 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
);
|
||||
}
|
||||
|
||||
private renderRadio() {
|
||||
private renderRadio(labelledby: string | undefined) {
|
||||
const inputs = this.processedInputs;
|
||||
|
||||
if (inputs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="alert-radio-group" role="radiogroup" aria-activedescendant={this.activeId}>
|
||||
<div class="alert-radio-group" role="radiogroup" aria-labelledby={labelledby} aria-activedescendant={this.activeId}>
|
||||
{ inputs.map(i => (
|
||||
<button
|
||||
type="button"
|
||||
@@ -463,13 +459,13 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
);
|
||||
}
|
||||
|
||||
private renderInput() {
|
||||
private renderInput(labelledby: string | undefined) {
|
||||
const inputs = this.processedInputs;
|
||||
if (inputs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div class="alert-input-group">
|
||||
<div class="alert-input-group" aria-labelledby={labelledby}>
|
||||
{ inputs.map(i => {
|
||||
if (i.type === 'textarea') {
|
||||
return (
|
||||
@@ -556,6 +552,13 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
|
||||
const msgId = `alert-${overlayIndex}-msg`;
|
||||
|
||||
let labelledById: string | undefined;
|
||||
if (header !== undefined) {
|
||||
labelledById = hdrId;
|
||||
} else if (subHeader !== undefined) {
|
||||
labelledById = subHdrId;
|
||||
}
|
||||
|
||||
return (
|
||||
<Host
|
||||
role="dialog"
|
||||
@@ -586,7 +589,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
|
||||
<div id={msgId} class="alert-message" innerHTML={sanitizeDOMString(this.message)}></div>
|
||||
|
||||
{this.renderAlertInputs()}
|
||||
{this.renderAlertInputs(labelledById)}
|
||||
{this.renderAlertButtons()}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -72,9 +72,6 @@ export class AlertExample {
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
|
||||
const { role } = await alert.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
async presentAlertMultipleButtons() {
|
||||
@@ -207,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: [
|
||||
@@ -288,9 +267,6 @@ export class AlertExample {
|
||||
type: 'checkbox',
|
||||
label: 'Checkbox 1',
|
||||
value: 'value1',
|
||||
handler: () => {
|
||||
console.log('Checkbox 1 selected');
|
||||
},
|
||||
checked: true
|
||||
},
|
||||
|
||||
@@ -298,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: [
|
||||
@@ -384,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() {
|
||||
@@ -516,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 = [
|
||||
@@ -590,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 = [
|
||||
@@ -666,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';
|
||||
|
||||
@@ -858,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={[
|
||||
@@ -938,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={[
|
||||
@@ -1037,9 +881,6 @@ export class AlertExample {
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
|
||||
const { role } = await alert.onDidDismiss();
|
||||
console.log('onDidDismiss resolved with role', role);
|
||||
}
|
||||
|
||||
async presentAlertMultipleButtons() {
|
||||
@@ -1172,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: [
|
||||
@@ -1253,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: [
|
||||
@@ -1373,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() {
|
||||
@@ -1501,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: [
|
||||
@@ -1577,9 +1362,6 @@ export default defineComponent({
|
||||
type: 'checkbox',
|
||||
label: 'Checkbox 1',
|
||||
value: 'value1',
|
||||
handler: () => {
|
||||
console.log('Checkbox 1 selected');
|
||||
},
|
||||
checked: true,
|
||||
},
|
||||
|
||||
@@ -1587,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: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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={[
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -13,7 +13,7 @@ export class App implements ComponentInterface {
|
||||
|
||||
componentDidLoad() {
|
||||
if (Build.isBrowser) {
|
||||
rIC(async () => {
|
||||
rIC(() => {
|
||||
const isHybrid = isPlatform(window, 'hybrid');
|
||||
if (!config.getBoolean('_testing')) {
|
||||
import('../../utils/tap-click').then(module => module.startTapClick(config));
|
||||
@@ -24,11 +24,8 @@ export class App implements ComponentInterface {
|
||||
if (config.getBoolean('inputShims', needInputShims())) {
|
||||
import('../../utils/input-shims/input-shims').then(module => module.startInputShims(config));
|
||||
}
|
||||
const hardwareBackButtonModule = await import('../../utils/hardware-back-button');
|
||||
if (config.getBoolean('hardwareBackButton', isHybrid)) {
|
||||
hardwareBackButtonModule.startHardwareBackButton();
|
||||
} else {
|
||||
hardwareBackButtonModule.blockHardwareBackButton();
|
||||
import('../../utils/hardware-back-button').then(module => module.startHardwareBackButton());
|
||||
}
|
||||
if (typeof (window as any) !== 'undefined') {
|
||||
import('../../utils/keyboard/keyboard').then(module => module.startKeyboardAssist(window));
|
||||
|
||||
@@ -67,7 +67,6 @@ export class Backdrop implements ComponentInterface {
|
||||
return (
|
||||
<Host
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
class={{
|
||||
[mode]: true,
|
||||
'backdrop-hide': !this.visible,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { AnimationBuilder, Color, RouterDirection } from '../../interface';
|
||||
import { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
|
||||
import { hasShadowDom, inheritAttributes } from '../../utils/helpers';
|
||||
import { hasShadowDom } from '../../utils/helpers';
|
||||
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
private inItem = false;
|
||||
private inListHeader = false;
|
||||
private inToolbar = false;
|
||||
private inheritedAttributes: { [k: string]: any } = {};
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@@ -135,7 +134,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
this.inToolbar = !!this.el.closest('ion-buttons');
|
||||
this.inListHeader = !!this.el.closest('ion-list-header');
|
||||
this.inItem = !!this.el.closest('ion-item') || !!this.el.closest('ion-item-divider');
|
||||
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
|
||||
}
|
||||
|
||||
private get hasIconOnly() {
|
||||
@@ -186,7 +184,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
|
||||
render() {
|
||||
const mode = getIonMode(this);
|
||||
const { buttonType, type, disabled, rel, target, size, href, color, expand, hasIconOnly, shape, strong, inheritedAttributes } = this;
|
||||
const { buttonType, type, disabled, rel, target, size, href, color, expand, hasIconOnly, shape, strong } = this;
|
||||
const finalSize = size === undefined && this.inItem ? 'small' : size;
|
||||
const TagType = href === undefined ? 'button' : 'a' as any;
|
||||
const attrs = (TagType === 'button')
|
||||
@@ -229,7 +227,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
disabled={disabled}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
{...inheritedAttributes}
|
||||
>
|
||||
<span class="button-inner">
|
||||
<slot name="icon-only"></slot>
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
<ion-button class="wide">wide</ion-button>
|
||||
<ion-button class="large">large</ion-button>
|
||||
<ion-button class="round">rounded</ion-button>
|
||||
<ion-button aria-label="this is my custom label">custom aria-label</ion-button>
|
||||
|
||||
<!-- Custom Colors -->
|
||||
<ion-button class="custom">custom</ion-button>
|
||||
|
||||
@@ -40,18 +40,8 @@
|
||||
--checkmark-color: #{current-color(contrast)};
|
||||
}
|
||||
|
||||
label {
|
||||
button {
|
||||
@include input-cover();
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
@include visually-hidden();
|
||||
}
|
||||
|
||||
.checkbox-icon {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { CheckboxChangeEventDetail, Color, StyleEventDetail } from '../../interface';
|
||||
import { getAriaLabel, renderHiddenInput } from '../../utils/helpers';
|
||||
import { findItemLabel, renderHiddenInput } from '../../utils/helpers';
|
||||
import { createColorClasses, hostContext } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
@@ -22,7 +22,7 @@ import { createColorClasses, hostContext } from '../../utils/theme';
|
||||
export class Checkbox implements ComponentInterface {
|
||||
|
||||
private inputId = `ion-cb-${checkboxIds++}`;
|
||||
private focusEl?: HTMLElement;
|
||||
private buttonEl?: HTMLElement;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@@ -54,11 +54,11 @@ export class Checkbox implements ComponentInterface {
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* The value of the checkbox does not mean if it's checked or not, use the `checked`
|
||||
* The value of the toggle does not mean if it's checked or not, use the `checked`
|
||||
* property for that.
|
||||
*
|
||||
* The value of a checkbox is analogous to the value of an `<input type="checkbox">`,
|
||||
* it's only used when the checkbox participates in a native `<form>`.
|
||||
* The value of a toggle is analogous to the value of a `<input type="checkbox">`,
|
||||
* it's only used when the toggle participates in a native `<form>`.
|
||||
*/
|
||||
@Prop() value = 'on';
|
||||
|
||||
@@ -68,12 +68,12 @@ export class Checkbox implements ComponentInterface {
|
||||
@Event() ionChange!: EventEmitter<CheckboxChangeEventDetail>;
|
||||
|
||||
/**
|
||||
* Emitted when the checkbox has focus.
|
||||
* Emitted when the toggle has focus.
|
||||
*/
|
||||
@Event() ionFocus!: EventEmitter<void>;
|
||||
|
||||
/**
|
||||
* Emitted when the checkbox loses focus.
|
||||
* Emitted when the toggle loses focus.
|
||||
*/
|
||||
@Event() ionBlur!: EventEmitter<void>;
|
||||
|
||||
@@ -109,14 +109,12 @@ export class Checkbox implements ComponentInterface {
|
||||
}
|
||||
|
||||
private setFocus() {
|
||||
if (this.focusEl) {
|
||||
this.focusEl.focus();
|
||||
if (this.buttonEl) {
|
||||
this.buttonEl.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private onClick = (ev: any) => {
|
||||
ev.preventDefault();
|
||||
|
||||
private onClick = () => {
|
||||
this.setFocus();
|
||||
this.checked = !this.checked;
|
||||
this.indeterminate = false;
|
||||
@@ -131,11 +129,14 @@ export class Checkbox implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { color, checked, disabled, el, indeterminate, inputId, name, value } = this;
|
||||
const { inputId, indeterminate, disabled, checked, value, color, el } = this;
|
||||
const labelId = inputId + '-lbl';
|
||||
const mode = getIonMode(this);
|
||||
const { label, labelId, labelText } = getAriaLabel(el, inputId);
|
||||
|
||||
renderHiddenInput(true, el, name, (checked ? value : ''), disabled);
|
||||
const label = findItemLabel(el);
|
||||
if (label) {
|
||||
label.id = labelId;
|
||||
}
|
||||
renderHiddenInput(true, el, this.name, (checked ? value : ''), disabled);
|
||||
|
||||
let path = indeterminate
|
||||
? <path d="M6 12L18 12" part="mark" />
|
||||
@@ -150,10 +151,10 @@ export class Checkbox implements ComponentInterface {
|
||||
return (
|
||||
<Host
|
||||
onClick={this.onClick}
|
||||
aria-labelledby={label ? labelId : null}
|
||||
aria-checked={`${checked}`}
|
||||
aria-hidden={disabled ? 'true' : null}
|
||||
role="checkbox"
|
||||
aria-disabled={disabled ? 'true' : null}
|
||||
aria-checked={`${checked}`}
|
||||
aria-labelledby={labelId}
|
||||
class={createColorClasses(color, {
|
||||
[mode]: true,
|
||||
'in-item': hostContext('ion-item', el),
|
||||
@@ -166,18 +167,14 @@ export class Checkbox implements ComponentInterface {
|
||||
<svg class="checkbox-icon" viewBox="0 0 24 24" part="container">
|
||||
{path}
|
||||
</svg>
|
||||
<label htmlFor={inputId}>
|
||||
{labelText}
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
aria-checked={`${checked}`}
|
||||
disabled={disabled}
|
||||
id={inputId}
|
||||
onFocus={() => this.onFocus()}
|
||||
onBlur={() => this.onBlur()}
|
||||
ref={focusEl => this.focusEl = focusEl}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
disabled={this.disabled}
|
||||
ref={btnEl => this.buttonEl = btnEl}
|
||||
>
|
||||
</button>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,8 +228,8 @@ export class CheckboxExample {
|
||||
<ion-label>{{entry.val}}</ion-label>
|
||||
<ion-checkbox
|
||||
slot="end"
|
||||
@update:modelValue="entry.isChecked = $event"
|
||||
:modelValue="entry.isChecked">
|
||||
@input="entry.checked = $event.target.value"
|
||||
:value="entry.isChecked">
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
@@ -266,16 +266,16 @@ export default defineComponent({
|
||||
| `indeterminate` | `indeterminate` | If `true`, the checkbox will visually appear as indeterminate. | `boolean` | `false` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `name` | `name` | The name of the control, which is submitted with the form data. | `string` | `this.inputId` |
|
||||
| `value` | `value` | The value of the checkbox does not mean if it's checked or not, use the `checked` property for that. The value of a checkbox is analogous to the value of an `<input type="checkbox">`, it's only used when the checkbox participates in a native `<form>`. | `string` | `'on'` |
|
||||
| `value` | `value` | The value of the toggle does not mean if it's checked or not, use the `checked` property for that. The value of a toggle is analogous to the value of a `<input type="checkbox">`, it's only used when the toggle participates in a native `<form>`. | `string` | `'on'` |
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Description | Type |
|
||||
| ----------- | ---------------------------------------------- | ---------------------------------------- |
|
||||
| `ionBlur` | Emitted when the checkbox loses focus. | `CustomEvent<void>` |
|
||||
| `ionBlur` | Emitted when the toggle loses focus. | `CustomEvent<void>` |
|
||||
| `ionChange` | Emitted when the checked property has changed. | `CustomEvent<CheckboxChangeEventDetail>` |
|
||||
| `ionFocus` | Emitted when the checkbox has focus. | `CustomEvent<void>` |
|
||||
| `ionFocus` | Emitted when the toggle has focus. | `CustomEvent<void>` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content id="content">
|
||||
<ion-item onClick="clickItem()">
|
||||
<ion-label>Clickable Item</ion-label>
|
||||
<ion-checkbox></ion-checkbox>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Default</ion-label>
|
||||
<ion-checkbox checked></ion-checkbox>
|
||||
@@ -43,7 +38,7 @@
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Secondary</ion-label>
|
||||
<ion-checkbox disabled checked color="secondary"></ion-checkbox>
|
||||
<ion-checkbox checked color="secondary"></ion-checkbox>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
@@ -108,35 +103,6 @@
|
||||
</ion-content>
|
||||
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
const inputs = document.querySelectorAll('ion-checkbox');
|
||||
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
const input = inputs[i];
|
||||
|
||||
input.addEventListener('ionBlur', function() {
|
||||
console.log('Listen ionBlur: fired');
|
||||
});
|
||||
|
||||
input.addEventListener('ionFocus', function() {
|
||||
console.log('Listen ionFocus: fired');
|
||||
});
|
||||
|
||||
input.addEventListener('ionChange', function(ev) {
|
||||
console.log('Listen ionChange: fired', ev.detail);
|
||||
});
|
||||
|
||||
input.addEventListener('click', function() {
|
||||
console.log('Listen click: fired');
|
||||
});
|
||||
}
|
||||
|
||||
const clickItem = () => {
|
||||
console.log('Item click: fired');
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -31,22 +31,22 @@
|
||||
<div class="ion-padding-start">
|
||||
<!-- Default to unchecked -->
|
||||
<label for="unchecked">Unchecked</label>
|
||||
<input name="unchecked" id="unchecked" type="checkbox">
|
||||
<input name="unchecked" type="checkbox">
|
||||
<br>
|
||||
|
||||
<!-- Default to checked -->
|
||||
<label for="checked">Checked</label>
|
||||
<input name="checked" id="checked" type="checkbox" checked />
|
||||
<input name="checked" type="checkbox" checked />
|
||||
<br>
|
||||
|
||||
<!-- Default to indeterminate -->
|
||||
<label for="indeterminate">Indeterminate</label>
|
||||
<input name="indeterminate" id="indeterminate" type="checkbox" class="indeterminate">
|
||||
<input name="indeterminate" type="checkbox" class="indeterminate">
|
||||
<br>
|
||||
|
||||
<!-- Default to checked / indeterminate -->
|
||||
<label for="both">Checked / Indeterminate</label>
|
||||
<input name="both" id="both" type="checkbox" checked class="indeterminate">
|
||||
<input name="both" type="checkbox" checked class="indeterminate">
|
||||
<br>
|
||||
</div>
|
||||
|
||||
@@ -81,15 +81,15 @@
|
||||
</ion-label>
|
||||
</ion-list-header>
|
||||
<div class="ion-padding-start">
|
||||
<ion-checkbox aria-label="Default Indeterminate" indeterminate></ion-checkbox>
|
||||
<ion-checkbox aria-label="Secondary Indeterminate" indeterminate color="secondary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Tertiary Indeterminate" indeterminate color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Success Indeterminate" indeterminate color="success"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Warning Indeterminate" indeterminate color="warning"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Danger Indeterminate" indeterminate color="danger"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Dark Indeterminate" indeterminate color="dark"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Medium Indeterminate" indeterminate color="medium"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Light Indeterminate" indeterminate color="light"></ion-checkbox>
|
||||
<ion-checkbox indeterminate></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="secondary"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="success"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="warning"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="danger"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="dark"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="medium"></ion-checkbox>
|
||||
<ion-checkbox indeterminate color="light"></ion-checkbox>
|
||||
</div>
|
||||
|
||||
<ion-list-header>
|
||||
@@ -100,20 +100,20 @@
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<ion-checkbox aria-labelledby="tall-label-0" indeterminate></ion-checkbox>
|
||||
<label id="tall-label-0">Tall Things</label>
|
||||
<ion-checkbox name="tall" id="tall" indeterminate></ion-checkbox>
|
||||
<label for="tall">Tall Things</label>
|
||||
<ul>
|
||||
<li>
|
||||
<ion-checkbox aria-labelledby="tall-label-1" checked></ion-checkbox>
|
||||
<label id="tall-label-1">Skyscrapers</label>
|
||||
<ion-checkbox name="tall-1" id="tall-1" checked></ion-checkbox>
|
||||
<label for="tall-1">Skyscrapers</label>
|
||||
</li>
|
||||
<li>
|
||||
<ion-checkbox aria-labelledby="tall-label-2"></ion-checkbox>
|
||||
<label id="tall-label-2">Trees</label>
|
||||
<ion-checkbox name="tall-2" id="tall-2"></ion-checkbox>
|
||||
<label for="tall-2">Trees</label>
|
||||
</li>
|
||||
<li>
|
||||
<ion-checkbox aria-labelledby="tall-label-3"></ion-checkbox>
|
||||
<label id="tall-label-3">Giants</label>
|
||||
<ion-checkbox name="tall-2" id="tall-2"></ion-checkbox>
|
||||
<label for="tall-2">Giants</label>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -13,67 +13,67 @@
|
||||
|
||||
<body class="ion-padding">
|
||||
<h1>Default</h1>
|
||||
<ion-checkbox aria-label="Default Checkbox"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Default Checkbox" checked></ion-checkbox>
|
||||
<ion-checkbox aria-label="Default Checkbox" disabled></ion-checkbox>
|
||||
<ion-checkbox aria-label="Default Checkbox" disabled checked></ion-checkbox>
|
||||
<ion-checkbox></ion-checkbox>
|
||||
<ion-checkbox checked></ion-checkbox>
|
||||
<ion-checkbox disabled></ion-checkbox>
|
||||
<ion-checkbox disabled checked></ion-checkbox>
|
||||
|
||||
<h1>Colors</h1>
|
||||
<ion-checkbox aria-label="Checkbox Primary" color="primary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Secondary" color="secondary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Tertiary" color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Success" color="success"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Warning" color="warning"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Danger" color="danger"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Light" color="light"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Medium" color="medium"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Dark" color="dark"></ion-checkbox>
|
||||
<ion-checkbox color="primary"></ion-checkbox>
|
||||
<ion-checkbox color="secondary"></ion-checkbox>
|
||||
<ion-checkbox color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox color="success"></ion-checkbox>
|
||||
<ion-checkbox color="warning"></ion-checkbox>
|
||||
<ion-checkbox color="danger"></ion-checkbox>
|
||||
<ion-checkbox color="light"></ion-checkbox>
|
||||
<ion-checkbox color="medium"></ion-checkbox>
|
||||
<ion-checkbox color="dark"></ion-checkbox>
|
||||
|
||||
<hr>
|
||||
|
||||
<ion-checkbox aria-label="Checkbox Primary" checked color="primary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Secondary" checked color="secondary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Tertiary" checked color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Success" checked color="success"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Warning" checked color="warning"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Danger" checked color="danger"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Light" checked color="light"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Medium" checked color="medium"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Dark" checked color="dark"></ion-checkbox>
|
||||
<ion-checkbox checked color="primary"></ion-checkbox>
|
||||
<ion-checkbox checked color="secondary"></ion-checkbox>
|
||||
<ion-checkbox checked color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox checked color="success"></ion-checkbox>
|
||||
<ion-checkbox checked color="warning"></ion-checkbox>
|
||||
<ion-checkbox checked color="danger"></ion-checkbox>
|
||||
<ion-checkbox checked color="light"></ion-checkbox>
|
||||
<ion-checkbox checked color="medium"></ion-checkbox>
|
||||
<ion-checkbox checked color="dark"></ion-checkbox>
|
||||
|
||||
<hr>
|
||||
|
||||
<ion-checkbox aria-label="Checkbox Primary" checked disabled color="primary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Secondary" checked disabled color="secondary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Tertiary" checked disabled color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Success" checked disabled color="success"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Warning" checked disabled color="warning"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Danger" checked disabled color="danger"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Light" checked disabled color="light"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Medium" checked disabled color="medium"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Dark" checked disabled color="dark"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="primary"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="secondary"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="tertiary"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="success"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="warning"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="danger"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="light"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="medium"></ion-checkbox>
|
||||
<ion-checkbox checked disabled color="dark"></ion-checkbox>
|
||||
|
||||
<h1>Custom</h1>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom" checked></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom" disabled></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom" disabled checked></ion-checkbox>
|
||||
<ion-checkbox class="custom"></ion-checkbox>
|
||||
<ion-checkbox class="custom" checked></ion-checkbox>
|
||||
<ion-checkbox class="custom" disabled></ion-checkbox>
|
||||
<ion-checkbox class="custom" disabled checked></ion-checkbox>
|
||||
|
||||
<h1>Custom: checked</h1>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom-checked"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom-checked" checked></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom-checked" disabled></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom" class="custom-checked" disabled checked></ion-checkbox>
|
||||
<ion-checkbox class="custom-checked"></ion-checkbox>
|
||||
<ion-checkbox class="custom-checked" checked></ion-checkbox>
|
||||
<ion-checkbox class="custom-checked" disabled></ion-checkbox>
|
||||
<ion-checkbox class="custom-checked" disabled checked></ion-checkbox>
|
||||
|
||||
<h1>Custom: light</h1>
|
||||
<ion-checkbox aria-label="Checkbox Custom Light" class="custom-light"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom Light" class="custom-light" checked></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom Light" class="custom-light" disabled></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom Light" class="custom-light" disabled checked></ion-checkbox>
|
||||
<ion-checkbox class="custom-light"></ion-checkbox>
|
||||
<ion-checkbox class="custom-light" checked></ion-checkbox>
|
||||
<ion-checkbox class="custom-light" disabled></ion-checkbox>
|
||||
<ion-checkbox class="custom-light" disabled checked></ion-checkbox>
|
||||
|
||||
<h1>Custom: transition</h1>
|
||||
<ion-checkbox aria-label="Checkbox Custom Transition" class="custom-transition"></ion-checkbox>
|
||||
<ion-checkbox aria-label="Checkbox Custom Transition" class="custom-transition" checked></ion-checkbox>
|
||||
<ion-checkbox class="custom-transition"></ion-checkbox>
|
||||
<ion-checkbox class="custom-transition" checked></ion-checkbox>
|
||||
|
||||
<style>
|
||||
.custom {
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
<ion-label>{{entry.val}}</ion-label>
|
||||
<ion-checkbox
|
||||
slot="end"
|
||||
@update:modelValue="entry.isChecked = $event"
|
||||
:modelValue="entry.isChecked">
|
||||
@input="entry.checked = $event.target.value"
|
||||
:value="entry.isChecked">
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
||||
@@ -37,11 +37,6 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:host(.chip-disabled) {
|
||||
cursor: default;
|
||||
opacity: .4;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Chip Colors
|
||||
// ---------------------------------------------
|
||||
|
||||
@@ -28,21 +28,14 @@ export class Chip implements ComponentInterface {
|
||||
*/
|
||||
@Prop() outline = false;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the chip.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
render() {
|
||||
const mode = getIonMode(this);
|
||||
|
||||
return (
|
||||
<Host
|
||||
aria-disabled={this.disabled ? 'true' : null}
|
||||
class={createColorClasses(this.color, {
|
||||
[mode]: true,
|
||||
'chip-outline': this.outline,
|
||||
'chip-disabled': this.disabled,
|
||||
'ion-activatable': true,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ Chips represent complex entities in small blocks, such as a contact. A chip can
|
||||
|
||||
## Usage
|
||||
|
||||
### Angular
|
||||
### Angular / javascript
|
||||
|
||||
```html
|
||||
<ion-chip>
|
||||
@@ -22,60 +22,6 @@ Chips represent complex entities in small blocks, such as a contact. A chip can
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip [disabled]="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="heart" color="dark"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-label>Button Chip</ion-label>
|
||||
<ion-icon name="close-circle"></ion-icon>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="pin" color="primary"></ion-icon>
|
||||
<ion-label>Icon Chip</ion-label>
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-avatar>
|
||||
<img src="https://gravatar.com/avatar/dba6bae8c566f9d4041fb9cd9ada7741?d=identicon&f=y">
|
||||
</ion-avatar>
|
||||
<ion-label>Avatar Chip</ion-label>
|
||||
<ion-icon name="close-circle"></ion-icon>
|
||||
</ion-chip>
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
|
||||
```html
|
||||
<ion-chip>
|
||||
<ion-label>Default</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-label color="secondary">Secondary Label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip color="secondary">
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip disabled="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
@@ -135,10 +81,6 @@ export const ChipExamples: React.FC = () => {
|
||||
<IonLabel color="dark">Secondary w/ Dark label</IonLabel>
|
||||
</IonChip>
|
||||
|
||||
<IonChip disabled={true}>
|
||||
<IonLabel>Disabled Chip</IonLabel>
|
||||
</IonChip>
|
||||
|
||||
<IonChip>
|
||||
<IonIcon icon={pin} />
|
||||
<IonLabel>Default</IonLabel>
|
||||
@@ -249,10 +191,6 @@ export class ChipExample {
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip :disabled="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon :icon="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
@@ -302,12 +240,11 @@ export default defineComponent({
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the chip. | `boolean` | `false` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `outline` | `outline` | Display an outline style button. | `boolean` | `false` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| --------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `outline` | `outline` | Display an outline style button. | `boolean` | `false` |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<ion-app>
|
||||
<ion-content>
|
||||
<h3>Default</h3>
|
||||
|
||||
<p>
|
||||
<ion-chip>
|
||||
<ion-label>Default</ion-label>
|
||||
@@ -196,26 +195,6 @@
|
||||
</ion-chip>
|
||||
</p>
|
||||
|
||||
<h3>Disabled</h3>
|
||||
|
||||
<p>
|
||||
<ion-chip disabled>
|
||||
<ion-label>Disabled</ion-label>
|
||||
</ion-chip>
|
||||
<ion-chip outline color="danger" class="ion-focused" disabled>
|
||||
<ion-label>Disabled Outline</ion-label>
|
||||
</ion-chip>
|
||||
<ion-chip color="secondary" class="ion-focused" disabled>
|
||||
<ion-icon name="checkmark-circle"></ion-icon>
|
||||
<ion-label>Disabled Secondary with Icon</ion-label>
|
||||
</ion-chip>
|
||||
<ion-chip outline class="ion-focused" disabled>
|
||||
<ion-icon name="git-pull-request"></ion-icon>
|
||||
<ion-label>Disabled Outline with Icon and Avatar</ion-label>
|
||||
<ion-icon name="close-circle"></ion-icon>
|
||||
</ion-chip>
|
||||
</p>
|
||||
|
||||
<h3>Custom</h3>
|
||||
|
||||
<!-- Custom Font -->
|
||||
@@ -267,6 +246,11 @@
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
ion-chip {
|
||||
display: inline-block !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.wide {
|
||||
--background: #d1f3ff;
|
||||
--background-hover: #add8e6;
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip [disabled]="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip disabled="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon name="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
|
||||
@@ -24,10 +24,6 @@ export const ChipExamples: React.FC = () => {
|
||||
<IonLabel color="dark">Secondary w/ Dark label</IonLabel>
|
||||
</IonChip>
|
||||
|
||||
<IonChip disabled={true}>
|
||||
<IonLabel>Disabled Chip</IonLabel>
|
||||
</IonChip>
|
||||
|
||||
<IonChip>
|
||||
<IonIcon icon={pin} />
|
||||
<IonLabel>Default</IonLabel>
|
||||
@@ -61,4 +57,4 @@ export const ChipExamples: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
```
|
||||
```
|
||||
@@ -12,10 +12,6 @@
|
||||
<ion-label color="dark">Secondary w/ Dark label</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip :disabled="true">
|
||||
<ion-label>Disabled Chip</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip>
|
||||
<ion-icon :icon="pin"></ion-icon>
|
||||
<ion-label>Default</ion-label>
|
||||
|
||||
@@ -100,9 +100,7 @@
|
||||
*
|
||||
* See: https://bugs.webkit.org/show_bug.cgi?id=216701
|
||||
*/
|
||||
z-index: 0;
|
||||
|
||||
will-change: scroll-position;
|
||||
will-change: scroll-position, transform;
|
||||
}
|
||||
|
||||
.scroll-y {
|
||||
|
||||
@@ -27,7 +27,6 @@ export class Content implements ComponentInterface {
|
||||
private cTop = -1;
|
||||
private cBottom = -1;
|
||||
private scrollEl!: HTMLElement;
|
||||
private isMainContent = true;
|
||||
|
||||
// Detail is used in a hot loop in the scroll event, by allocating it here
|
||||
// V8 will be able to inline any read/write to it since it's a monomorphic class.
|
||||
@@ -106,10 +105,6 @@ export class Content implements ComponentInterface {
|
||||
*/
|
||||
@Event() ionScrollEnd!: EventEmitter<ScrollBaseDetail>;
|
||||
|
||||
connectedCallback() {
|
||||
this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.onScrollEnd();
|
||||
}
|
||||
@@ -309,10 +304,9 @@ export class Content implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isMainContent, scrollX, scrollY } = this;
|
||||
const { scrollX, scrollY } = this;
|
||||
const mode = getIonMode(this);
|
||||
const forceOverscroll = this.shouldForceOverscroll();
|
||||
const TagType = isMainContent ? 'main' : 'div' as any;
|
||||
const transitionShadow = (mode === 'ios' && config.getBoolean('experimentalTransitionShadow', true));
|
||||
|
||||
this.resize();
|
||||
@@ -330,19 +324,19 @@ export class Content implements ComponentInterface {
|
||||
}}
|
||||
>
|
||||
<div id="background-content" part="background"></div>
|
||||
<TagType
|
||||
<main
|
||||
class={{
|
||||
'inner-scroll': true,
|
||||
'scroll-x': scrollX,
|
||||
'scroll-y': scrollY,
|
||||
'overscroll': (scrollX || scrollY) && forceOverscroll
|
||||
}}
|
||||
ref={(el: HTMLElement) => this.scrollEl = el!}
|
||||
onScroll={(this.scrollEvents) ? (ev: UIEvent) => this.onScroll(ev) : undefined}
|
||||
ref={el => this.scrollEl = el!}
|
||||
onScroll={(this.scrollEvents) ? ev => this.onScroll(ev) : undefined}
|
||||
part="scroll"
|
||||
>
|
||||
<slot></slot>
|
||||
</TagType>
|
||||
</main>
|
||||
|
||||
{transitionShadow ? (
|
||||
<div class="transition-effect">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user