chore(): sync with main
261
.github/PROCESS.md
vendored
@ -1,261 +0,0 @@
|
|||||||
# Process
|
|
||||||
|
|
||||||
This document is to describe the internal process that the Ionic team uses for issue management, project planning and the development workflow.
|
|
||||||
|
|
||||||
## Table of contents
|
|
||||||
* [Project Boards](#project-boards)
|
|
||||||
* [Managing Issues](#managing-issues)
|
|
||||||
* [Workflow](#workflow)
|
|
||||||
* [Releasing](#releasing)
|
|
||||||
|
|
||||||
## Project Boards
|
|
||||||
|
|
||||||
The project boards are located under the `Projects` tab in GitHub: https://github.com/ionic-team/ionic/projects/
|
|
||||||
|
|
||||||
### Core Project Board
|
|
||||||
|
|
||||||
The `Core` project board contains issues related to the `@ionic/core` package. A description of each column is below.
|
|
||||||
|
|
||||||
#### Backlog :robot:
|
|
||||||
|
|
||||||
Contains up to 20 issues that are important to work on soon but we don't think we can fit in the current sprint. If we finish everything we planned for the week we can pull from this column. Issues will automatically move to this column when they are added to the project board.
|
|
||||||
|
|
||||||
#### On Deck :baseball:
|
|
||||||
|
|
||||||
Contains issues that we believe we can accomplish in the current sprint. Issues should be manually moved to this column when we have our sprint planning meeting.
|
|
||||||
|
|
||||||
#### In Progress :person_fencing:
|
|
||||||
|
|
||||||
Issues and pull requests that are currently being worked on. Issues should be manually moved to this column and assigned to yourself when you begin working on them. Pull requests are automatically added to this column when added to the project board.
|
|
||||||
|
|
||||||
#### Needs Review :thinking:
|
|
||||||
|
|
||||||
Issues and pull requests that need review. Pull requests will automatically move here when a reviewer requests changes, or it no longer meets the minimum number of required approving reviews.
|
|
||||||
|
|
||||||
#### Done :tada:
|
|
||||||
|
|
||||||
Issues and pull requests that are completed. Issues will automatically move here when they are closed. Pull requests will automatically moved here when they are merged or closed with unmerged commits.
|
|
||||||
|
|
||||||
|
|
||||||
## Managing Issues
|
|
||||||
|
|
||||||
### Issues to Triage
|
|
||||||
|
|
||||||
The issues that need to be triaged all have the `triage` label. In many cases the issue can be automatically processed by the Ionic Issue Bot by applying a specific label.
|
|
||||||
|
|
||||||
Once another label is applied to the issue, the `triage` label is automatically removed by the bot.
|
|
||||||
|
|
||||||
### Wrong Repository
|
|
||||||
|
|
||||||
If an issue does not pertain to the Ionic Framework but does pertain to another repository, it should be moved to that repository. The bot has been set up to automatically create the issue in other repositories while closing and locking the issue in this repository. Use one of the following labels to perform that action:
|
|
||||||
|
|
||||||
- ionitron: cli
|
|
||||||
- ionitron: docs
|
|
||||||
- ionitron: stencil
|
|
||||||
- ionitron: native
|
|
||||||
|
|
||||||
### Ionic Appflow Issues
|
|
||||||
|
|
||||||
If the issue is associated with Ionic Appflow the submitter should be told to use the [Ionic Appflow Support Forum](https://ionic.zendesk.com/hc/en-us/requests/new). The issue should be closed and locked. Use the `ionitron: ionic appflow` label to accomplish this.
|
|
||||||
|
|
||||||
### Support Questions
|
|
||||||
|
|
||||||
If the issue is a support question, the submitter should be redirected to our [forum](https://forum.ionicframework.com). The issue should be closed and locked. Use the `ionitron: support` label to accomplish this.
|
|
||||||
|
|
||||||
### Incomplete Template
|
|
||||||
|
|
||||||
If the issue template has not been filled out completely, the issue should be closed and locked. The submitter should be informed to re-submit the issue making sure they fill the form out completely. Use the `ionitron: missing template` label to accomplish this.
|
|
||||||
|
|
||||||
### Issues with Open Questions
|
|
||||||
|
|
||||||
In many cases, the template is mostly filled out but just missing a thing or two or you may have a question or need clarification. In such a case, the submitter should be asked to supply that information.
|
|
||||||
|
|
||||||
1. add a comment requesting the additional information or clarification
|
|
||||||
1. add the `needs: reply` label to the task
|
|
||||||
|
|
||||||
NOTE: be sure to perform those actions in the order stated. If you add the comment second it will trigger the removal of the label.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
We have two long-living branches:
|
|
||||||
|
|
||||||
- `main`: completed features, bug fixes, refactors, chores
|
|
||||||
- `stable`: the latest release
|
|
||||||
|
|
||||||
The overall flow:
|
|
||||||
|
|
||||||
1. Feature, refactor, and bug fix branches are created from `main`
|
|
||||||
1. When a feature, refactor, or fix is complete it is merged into `main`
|
|
||||||
1. A release branch is created from `main`
|
|
||||||
1. When the release branch is done it is merged into `main` and `stable`
|
|
||||||
1. If an issue in `stable` is detected a hotfix branch is created from `stable`
|
|
||||||
1. Once the hotfix is complete it is merged to both `main` and `stable`
|
|
||||||
1. All branches should follow the syntax of `{type}-{details}` where `{type}` is the type of branch (`hotfix`, `release`, or one of the [commit types](https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md#commit-message-format)) and `{details}` is a few hyphen separated words explaining the branch
|
|
||||||
|
|
||||||
### Stable and Main Branches
|
|
||||||
|
|
||||||
#### Stable Branch
|
|
||||||
|
|
||||||
Branches created from `stable`:
|
|
||||||
|
|
||||||
The following branch should be merged back to **both** `main` and `stable`:
|
|
||||||
|
|
||||||
- A `hotfix` branch (e.g. `hotfix-missing-export`): a bug fix that is fixing a regression or issue with a published release
|
|
||||||
|
|
||||||
A `hotfix` branch should be the **only** branch that is created from stable.
|
|
||||||
|
|
||||||
#### Main Branch
|
|
||||||
|
|
||||||
Branches created from `main`:
|
|
||||||
|
|
||||||
The following branches should be merged back to `main` via a pull request:
|
|
||||||
|
|
||||||
1. A feature branch (e.g. `feat-desktop-support`): an addition to the API that is not a bug fix or regression fix
|
|
||||||
1. A bug fix branch (e.g. `fix-tab-color`): a bug fix that is not fixing a regression or issue with a published release
|
|
||||||
1. All other types listed in the [commit message types](https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md#commit-message-format): `docs`, `style`, `refactor`, `perf`, `test`, `chore`
|
|
||||||
|
|
||||||
The following branch should be merged back to **both** `main` and `stable`:
|
|
||||||
|
|
||||||
1. A `release` branch (e.g. `release-4.1.x`): contains all fixes and (optionally) features that are tested and should go into the release
|
|
||||||
|
|
||||||
|
|
||||||
### Feature Branches
|
|
||||||
|
|
||||||
Each new feature should reside in its own branch, based on the `main` branch. When a feature is complete, it should go into a pull request that gets merged back into `main`. A pull request adding a feature should be approved by two team members. Features should never interact directly with `stable`.
|
|
||||||
|
|
||||||
|
|
||||||
### Release Branches
|
|
||||||
|
|
||||||
Once `main` has acquired enough features for a release (or a predetermined release date is approaching), fork a release branch off of `main`. Creating this branch starts the next release cycle, so no new features can be added after this point - only bug fixes, documentation generation, and other release-oriented tasks should go in this branch.
|
|
||||||
|
|
||||||
Once the release is ready to ship, it will get merged into `stable` and `main`, then the release branch will be deleted. It’s important to merge back into `main` because critical updates may have been added to the release branch and they need to be accessible to new features. This should be done in a pull request after review.
|
|
||||||
|
|
||||||
See the [steps for releasing](#releasing) below for detailed information on how to publish a release.
|
|
||||||
|
|
||||||
### Version Branches
|
|
||||||
|
|
||||||
Once a release has shipped and the release branch has been merged into `stable` and `main` it should also be merged into its corresponding version branch. These version branches allow us to ship updates for specific versions of the framework (i.e. Lets us ship a bug fix that only affects 4.2.x).
|
|
||||||
|
|
||||||
Patch releases should be merged into their corresponding version branches. For example, a `release-4.1.1` branch should be merged into the `4.1.x` version branch and a `release-5.0.1` branch should be merged into the `5.0.x` version branch.
|
|
||||||
|
|
||||||
When releasing a major version such as `5.0.0 ` or a minor version such as `4.1.0` , the version branch will not exist. The version branch should be created once the release branch has been merged into `stable` and `main`. For example, when releasing `4.1.0`, the `release-4.1.0` release branch should be merged into `stable` and `main` and then the `4.1.x` version branch should be created off the latest `stable`.
|
|
||||||
|
|
||||||
|
|
||||||
### Hotfix Branches
|
|
||||||
|
|
||||||
Maintenance or “hotfix” branches are used to quickly patch production releases. This is the only branch that should fork directly off of `stable`. As soon as the fix is complete, it should be merged into both `stable` and `main` (or the current release branch).
|
|
||||||
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
#### Making a Change
|
|
||||||
|
|
||||||
1. Create a branch from `main`.
|
|
||||||
1. Make changes. Limit your changes to a "unit of work", meaning don't include irrelevant changes that may confuse and delay the change.
|
|
||||||
1. Push changes.
|
|
||||||
1. Create a PR with the base of `main`.
|
|
||||||
1. Have someone approve your change (optional right now--at your discretion).
|
|
||||||
|
|
||||||
<img width="236" alt="image" src="https://user-images.githubusercontent.com/236501/47031893-913e0480-d136-11e8-9d9a-4b6297a4d7ba.png">
|
|
||||||
|
|
||||||
1. Wait for status checks to succeed. Fix errors if any occur.
|
|
||||||
|
|
||||||
<img width="223" alt="All checks have passed" src="https://user-images.githubusercontent.com/236501/47031830-62c02980-d136-11e8-9055-08af1b717304.png">
|
|
||||||
|
|
||||||
1. Click **Squash and merge**. Use the dropdown to select this option if necessary.
|
|
||||||
|
|
||||||
<img width="192" alt="Squash and merge button" src="https://user-images.githubusercontent.com/236501/47031620-da418900-d135-11e8-91ff-e84f2478b2b3.png">
|
|
||||||
|
|
||||||
1. During confirmation, rewrite the commit message using our [Commit Message Format guidelines](https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md#commit-message-format). Keep the `(#1234)` at the end; it will create a link to the PR in the commit history and `CHANGELOG.md`. This is where commits on `main` become permanent.
|
|
||||||
|
|
||||||
<img width="672" alt="Squash and merge confirmation" src="https://user-images.githubusercontent.com/236501/47031753-31dff480-d136-11e8-9116-03934961bdc2.png">
|
|
||||||
|
|
||||||
1. Confirm squash and merge into `main`.
|
|
||||||
|
|
||||||
#### Updating from `main`
|
|
||||||
|
|
||||||
1. Pull the latest changes locally.
|
|
||||||
1. Merge the changes, fixing any conflicts.
|
|
||||||
1. Push the merged changes.
|
|
||||||
|
|
||||||
OR
|
|
||||||
|
|
||||||
1. Click **Update branch** on the PR:
|
|
||||||
|
|
||||||
<img width="672" alt="Update branch button" src="https://user-images.githubusercontent.com/236501/47032205-66a07b80-d137-11e8-8c9b-ee37d2d147c9.png">
|
|
||||||
|
|
||||||
1. Pull the merged changes locally.
|
|
||||||
|
|
||||||
#### Hotfixes
|
|
||||||
|
|
||||||
Hotfixes bypass `main` and should only be used for urgent fixes that can't wait for the next release to be ready.
|
|
||||||
|
|
||||||
1. Create a branch from `stable`.
|
|
||||||
1. Make changes.
|
|
||||||
1. Run `npm run release.prepare`.
|
|
||||||
1. Push changes.
|
|
||||||
1. Create a PR, making sure the PR will merge into `stable`.
|
|
||||||
1. Click **Squash and merge**. Use the dropdown to select this option if necessary.
|
|
||||||
|
|
||||||
<img width="192" alt="Squash and merge button" src="https://user-images.githubusercontent.com/236501/47031620-da418900-d135-11e8-91ff-e84f2478b2b3.png">
|
|
||||||
|
|
||||||
1. During confirmation, rewrite the commit message using our [Commit Message Format guidelines](https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md#commit-message-format). Keep the `(#1234)` at the end; it will create a link to the PR in the commit history and `CHANGELOG.md`. This is where commits on `main` become permanent.
|
|
||||||
|
|
||||||
<img width="672" alt="Squash and merge confirmation" src="https://user-images.githubusercontent.com/236501/47031753-31dff480-d136-11e8-9116-03934961bdc2.png">
|
|
||||||
|
|
||||||
1. Confirm squash and merge into `stable`.
|
|
||||||
1. CI builds `stable`, performing the release.
|
|
||||||
1. Create a PR to merge `stable` into `main`.
|
|
||||||
1. Click **Merge pull request**. Use the dropdown to select this option if necessary.
|
|
||||||
|
|
||||||
<img width="191" alt="Merge pull request button" src="https://user-images.githubusercontent.com/236501/47032669-8be1b980-d138-11e8-9a90-d1518c223184.png">
|
|
||||||
|
|
||||||
|
|
||||||
## Releasing
|
|
||||||
|
|
||||||
1. Create the release branch from `main`, for example: `release-4.5.0`.
|
|
||||||
|
|
||||||
1. For major or minor releases, create a version branch based off the latest version branch. For example, if releasing 4.5.0, create a branch called `4.5.x` based off `4.4.x`.
|
|
||||||
|
|
||||||
1. Submit a pull request from the release branch into the version branch. Do not merge this pull request yet.
|
|
||||||
|
|
||||||
1. Verify all tests are passing, fix any bugs if needed and make sure no undesired commits are in.
|
|
||||||
|
|
||||||
1. Navigate to the root of the repository while on the release branch.
|
|
||||||
|
|
||||||
1. Run `npm i` if it hasn't already been done.
|
|
||||||
|
|
||||||
1. Run `npm run release.prepare`
|
|
||||||
- Select the version based on the type of commits and the [Ionic Versioning](https://ionicframework.com/docs/intro/versioning)
|
|
||||||
- After the process completes, verify the version number in all packages (`core`, `docs`, `angular`)
|
|
||||||
- Verify the changelog commits are accurate and follow the [proper format]((https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md#commit-message-format))
|
|
||||||
- For major or minor releases, ensure that the version number has an associated title (for example: `4.5.0 Boron`)
|
|
||||||
- Commit these changes with the version number as the message, e.g. `git commit -m "4.5.0"`
|
|
||||||
|
|
||||||
1. *(Optional)* Run `npm run release -- --dry-run` to run the release without publishing and verify the version.
|
|
||||||
|
|
||||||
1. Run `npm run release`
|
|
||||||
|
|
||||||
1. Click **Merge pull request**. Use the dropdown to select this option if necessary.
|
|
||||||
|
|
||||||
<img width="191" alt="Merge pull request button" src="https://user-images.githubusercontent.com/236501/47032669-8be1b980-d138-11e8-9a90-d1518c223184.png">
|
|
||||||
|
|
||||||
1. Rewrite the commit message to `merge release-[VERSION]` with the proper release branch. For example, if this release is for `4.5.0`, the message would be `merge release-4.5.0`.
|
|
||||||
|
|
||||||
1. Submit a pull request from the release branch into `main`. Merge this pull request using the same commit format in the last step, to ensure any changes made on the release branch get added to future releases.
|
|
@ -1,5 +1,8 @@
|
|||||||
name: 'Test Vue E2E'
|
name: 'Test Vue E2E'
|
||||||
description: 'Test Vue E2E'
|
description: 'Test Vue E2E'
|
||||||
|
inputs:
|
||||||
|
app:
|
||||||
|
description: 'The specific test application'
|
||||||
runs:
|
runs:
|
||||||
using: 'composite'
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
@ -29,19 +32,23 @@ runs:
|
|||||||
name: ionic-vue-router
|
name: ionic-vue-router
|
||||||
path: ./packages/vue-router
|
path: ./packages/vue-router
|
||||||
filename: VueRouterBuild.zip
|
filename: VueRouterBuild.zip
|
||||||
|
- name: Create Test App
|
||||||
|
run: ./build.sh ${{ inputs.app }}
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./packages/vue/test
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./packages/vue/test-app
|
working-directory: ./packages/vue/test/build/${{ inputs.app }}
|
||||||
- name: Sync
|
- name: Sync
|
||||||
run: npm run sync
|
run: npm run sync
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./packages/vue/test-app
|
working-directory: ./packages/vue/test/build/${{ inputs.app }}
|
||||||
- name: Run Spec Tests
|
- name: Run Spec Tests
|
||||||
run: npm run test:unit
|
run: npm run test:unit
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./packages/vue/test-app
|
working-directory: ./packages/vue/test/build/${{ inputs.app }}
|
||||||
- name: Run E2E Tests
|
- name: Run E2E Tests
|
||||||
run: npm run test:e2e
|
run: npm run test:e2e
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./packages/vue/test-app
|
working-directory: ./packages/vue/test/build/${{ inputs.app }}
|
||||||
|
15
.github/workflows/build.yml
vendored
@ -106,11 +106,26 @@ jobs:
|
|||||||
- uses: ./.github/workflows/actions/build-vue-router
|
- uses: ./.github/workflows/actions/build-vue-router
|
||||||
|
|
||||||
test-vue-e2e:
|
test-vue-e2e:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
apps: [vue3]
|
||||||
needs: [build-vue, build-vue-router]
|
needs: [build-vue, build-vue-router]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: ./.github/workflows/actions/test-vue-e2e
|
- uses: ./.github/workflows/actions/test-vue-e2e
|
||||||
|
with:
|
||||||
|
app: ${{ matrix.apps }}
|
||||||
|
|
||||||
|
verify-test-vue-e2e:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: test-vue-e2e
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check build matrix status
|
||||||
|
if: ${{ needs.test-vue-e2e.result != 'success' }}
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
build-angular:
|
build-angular:
|
||||||
needs: [build-core]
|
needs: [build-core]
|
||||||
|
3
.gitignore
vendored
@ -74,4 +74,7 @@ angular/css/
|
|||||||
angular/test/build/
|
angular/test/build/
|
||||||
.angular/
|
.angular/
|
||||||
|
|
||||||
|
# vue
|
||||||
|
packages/vue/test/build/
|
||||||
|
|
||||||
.npmrc
|
.npmrc
|
||||||
|
37
CHANGELOG.md
@ -3,6 +3,43 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [6.2.5](https://github.com/ionic-team/ionic-framework/compare/v6.2.4...v6.2.5) (2022-08-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **action-sheet:** add aria-labelledby ([#25837](https://github.com/ionic-team/ionic-framework/issues/25837)) ([5270151](https://github.com/ionic-team/ionic-framework/commit/527015184e9413c1037277d3197bcaa33044c38c))
|
||||||
|
* **angular:** router outlet has mode property ([#25816](https://github.com/ionic-team/ionic-framework/issues/25816)) ([afd0bbc](https://github.com/ionic-team/ionic-framework/commit/afd0bbc60aa8f4edc88dc311d6484ac60117fce5)), closes [#25813](https://github.com/ionic-team/ionic-framework/issues/25813)
|
||||||
|
* **datetime:** next and previous buttons have correct labels ([#25845](https://github.com/ionic-team/ionic-framework/issues/25845)) ([41e3387](https://github.com/ionic-team/ionic-framework/commit/41e338730d32837fc9dd8a15477e37dea4cc76c9)), closes [#25844](https://github.com/ionic-team/ionic-framework/issues/25844)
|
||||||
|
* **datetime:** only log out of bounds warning if value set ([#25835](https://github.com/ionic-team/ionic-framework/issues/25835)) ([85af6ce](https://github.com/ionic-team/ionic-framework/commit/85af6ce436890eb922d2ba32053fb8b8bc7fd4ff)), closes [#25833](https://github.com/ionic-team/ionic-framework/issues/25833)
|
||||||
|
* **input:** clear button is not activated on swipe ([#25825](https://github.com/ionic-team/ionic-framework/issues/25825)) ([ff71ad4](https://github.com/ionic-team/ionic-framework/commit/ff71ad492d7671f8e550da7e08dbde30cb05ebf7)), closes [#24857](https://github.com/ionic-team/ionic-framework/issues/24857)
|
||||||
|
* **modal:** handleBehavior can be used with controller ([#25821](https://github.com/ionic-team/ionic-framework/issues/25821)) ([79ef1b5](https://github.com/ionic-team/ionic-framework/commit/79ef1b57dc74fd856ed7c2904d7400d283cc081e)), closes [#25820](https://github.com/ionic-team/ionic-framework/issues/25820)
|
||||||
|
* **searchbar:** clear button has focus indicator ([#25828](https://github.com/ionic-team/ionic-framework/issues/25828)) ([373b4ff](https://github.com/ionic-team/ionic-framework/commit/373b4ffe216ba584b92014cef501f64668e1f177))
|
||||||
|
* **searchbar:** keypress can activate clear button ([#25824](https://github.com/ionic-team/ionic-framework/issues/25824)) ([c270756](https://github.com/ionic-team/ionic-framework/commit/c270756356c7b23a1959ac5f4b8206a5cd1825c2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [6.2.4](https://github.com/ionic-team/ionic-framework/compare/v6.2.3...v6.2.4) (2022-08-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **alert:** add default aria-label ([#25800](https://github.com/ionic-team/ionic-framework/issues/25800)) ([d395a73](https://github.com/ionic-team/ionic-framework/commit/d395a73cb6c419e6c0072746b8e4768cd5f78ef3))
|
||||||
|
* **alert:** use aria-labelledby and aria-describedby instead of aria-label ([#25805](https://github.com/ionic-team/ionic-framework/issues/25805)) ([27318d7](https://github.com/ionic-team/ionic-framework/commit/27318d75df60dfce1a90f23ba31ea2b6636ba42f))
|
||||||
|
* **breadcrumb:** separator is not announced by narrators ([#25796](https://github.com/ionic-team/ionic-framework/issues/25796)) ([71fad38](https://github.com/ionic-team/ionic-framework/commit/71fad3884bc55b266067efb346500c848b856946))
|
||||||
|
* **datetime:** close month/year picker when hidden ([#25789](https://github.com/ionic-team/ionic-framework/issues/25789)) ([3b211b6](https://github.com/ionic-team/ionic-framework/commit/3b211b60fd9a88be6e232f839ecc4be090181530)), closes [#25787](https://github.com/ionic-team/ionic-framework/issues/25787)
|
||||||
|
* **modal:** role attribute can be customized ([#25804](https://github.com/ionic-team/ionic-framework/issues/25804)) ([037d579](https://github.com/ionic-team/ionic-framework/commit/037d579b2a3a660358f1e9c9b020c9510bb9c6b0))
|
||||||
|
* **react:** duplicate page transitions do not happen on react 18 ([#25798](https://github.com/ionic-team/ionic-framework/issues/25798)) ([a39d776](https://github.com/ionic-team/ionic-framework/commit/a39d776f087514b7fa744f44ce8ce2a04ed8aa43)), closes [#25797](https://github.com/ionic-team/ionic-framework/issues/25797)
|
||||||
|
* **refresher:** use componentOnReady utility for CE build ([#25783](https://github.com/ionic-team/ionic-framework/issues/25783)) ([bd715a5](https://github.com/ionic-team/ionic-framework/commit/bd715a52562f1f175d4bb6ea2dbfdd67a3e91db1)), closes [#25782](https://github.com/ionic-team/ionic-framework/issues/25782)
|
||||||
|
* **select:** compareWith passes params in correct order ([#25764](https://github.com/ionic-team/ionic-framework/issues/25764)) ([d631195](https://github.com/ionic-team/ionic-framework/commit/d6311951243fd9b867ae5d4a7a08c8d341f8eb7a)), closes [#25759](https://github.com/ionic-team/ionic-framework/issues/25759)
|
||||||
|
* **vue:** lifecycles now fire on tabs pages ([#25786](https://github.com/ionic-team/ionic-framework/issues/25786)) ([3020005](https://github.com/ionic-team/ionic-framework/commit/30200051bbab6ce57fd363668dafc49287c87c56)), closes [#25784](https://github.com/ionic-team/ionic-framework/issues/25784)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [6.2.3](https://github.com/ionic-team/ionic-framework/compare/v6.2.2...v6.2.3) (2022-08-17)
|
## [6.2.3](https://github.com/ionic-team/ionic-framework/compare/v6.2.2...v6.2.3) (2022-08-17)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,25 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [6.2.5](https://github.com/ionic-team/ionic/compare/v6.2.4...v6.2.5) (2022-08-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **angular:** router outlet has mode property ([#25816](https://github.com/ionic-team/ionic/issues/25816)) ([afd0bbc](https://github.com/ionic-team/ionic/commit/afd0bbc60aa8f4edc88dc311d6484ac60117fce5)), closes [#25813](https://github.com/ionic-team/ionic/issues/25813)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [6.2.4](https://github.com/ionic-team/ionic/compare/v6.2.3...v6.2.4) (2022-08-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ionic/angular
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [6.2.3](https://github.com/ionic-team/ionic/compare/v6.2.2...v6.2.3) (2022-08-17)
|
## [6.2.3](https://github.com/ionic-team/ionic/compare/v6.2.2...v6.2.3) (2022-08-17)
|
||||||
|
|
||||||
**Note:** Version bump only for package @ionic/angular
|
**Note:** Version bump only for package @ionic/angular
|
||||||
|
69
angular/package-lock.json
generated
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@ionic/angular",
|
"name": "@ionic/angular",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@ionic/angular",
|
"name": "@ionic/angular",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ionic/core": "^6.2.3",
|
"@ionic/core": "^6.2.5",
|
||||||
"jsonc-parser": "^3.0.0",
|
"jsonc-parser": "^3.0.0",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
@ -1023,15 +1023,27 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@ionic/core": {
|
"node_modules/@ionic/core": {
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.2.5.tgz",
|
||||||
"integrity": "sha512-TqSVN5nfDC8Ovcfgv6PH6FsNY8P9Awl2zSXVMBpgr5CSFNOb6xB4U8utdhMtJbuo/OYgqAbjSVq+pD4RiBt1rw==",
|
"integrity": "sha512-PLnG182RYydXB71cjkMk2TLxFVKabvEc9wjeK5SsvxI1/QE9+wPfxDnvKWag8UeXgaGUhby1bitWkV5pniDaXA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stencil/core": "^2.16.0",
|
"@stencil/core": "^2.17.4",
|
||||||
"ionicons": "^6.0.2",
|
"ionicons": "^6.0.3",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ionic/core/node_modules/@stencil/core": {
|
||||||
|
"version": "2.17.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.17.4.tgz",
|
||||||
|
"integrity": "sha512-SGRlHpjV1RyFvzw6jFMVKpLNox9Eds3VvpbpD2SW9CuxdLonHDSFtQks5zmT4zs1Rse9I6kFc2mFK/dHNTalkg==",
|
||||||
|
"bin": {
|
||||||
|
"stencil": "bin/stencil"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.10.0",
|
||||||
|
"npm": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ionic/eslint-config": {
|
"node_modules/@ionic/eslint-config": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/eslint-config/-/eslint-config-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/eslint-config/-/eslint-config-0.3.0.tgz",
|
||||||
@ -1222,9 +1234,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@stencil/core": {
|
"node_modules/@stencil/core": {
|
||||||
"version": "2.16.0",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.16.1.tgz",
|
||||||
"integrity": "sha512-oKxPYxpH1no0oMFSf8EesuFBcn9hVpoqrpiS2WH0H50RKKL8hhKoxDfn/cNeD12L0Aj7kf6nNtexIllmkYG6lw==",
|
"integrity": "sha512-s/UJp9qxExL3DyQPT70kiuWeb3AdjbUZM+5lEIXn30I2DLcLYPOPXfsoWJODieQywq+3vPiLZeIdkoqjf6jcSw==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"stencil": "bin/stencil"
|
"stencil": "bin/stencil"
|
||||||
},
|
},
|
||||||
@ -3557,9 +3569,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ionicons": {
|
"node_modules/ionicons": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.3.tgz",
|
||||||
"integrity": "sha512-AyKfFaUKVoBz4eB8XkU7H1R5HFnVsgq5ijqSdbXC0lES9PDK/J6LUQz6XUJq0mVVQF5k9kczSPOLMW3mszG0mQ==",
|
"integrity": "sha512-kVOWER991EMqLiVShrCSWKMHkgHZP7XfVdyN6YPMuoO33W7pc5CPNVNfR8OMe/I8rYEbaunyBs6dXNYpR6gGZw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stencil/core": "~2.16.0"
|
"@stencil/core": "~2.16.0"
|
||||||
}
|
}
|
||||||
@ -7939,13 +7951,20 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@ionic/core": {
|
"@ionic/core": {
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-6.2.5.tgz",
|
||||||
"integrity": "sha512-TqSVN5nfDC8Ovcfgv6PH6FsNY8P9Awl2zSXVMBpgr5CSFNOb6xB4U8utdhMtJbuo/OYgqAbjSVq+pD4RiBt1rw==",
|
"integrity": "sha512-PLnG182RYydXB71cjkMk2TLxFVKabvEc9wjeK5SsvxI1/QE9+wPfxDnvKWag8UeXgaGUhby1bitWkV5pniDaXA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@stencil/core": "^2.16.0",
|
"@stencil/core": "^2.17.4",
|
||||||
"ionicons": "^6.0.2",
|
"ionicons": "^6.0.3",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@stencil/core": {
|
||||||
|
"version": "2.17.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.17.4.tgz",
|
||||||
|
"integrity": "sha512-SGRlHpjV1RyFvzw6jFMVKpLNox9Eds3VvpbpD2SW9CuxdLonHDSFtQks5zmT4zs1Rse9I6kFc2mFK/dHNTalkg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ionic/eslint-config": {
|
"@ionic/eslint-config": {
|
||||||
@ -8092,9 +8111,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@stencil/core": {
|
"@stencil/core": {
|
||||||
"version": "2.16.0",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.16.1.tgz",
|
||||||
"integrity": "sha512-oKxPYxpH1no0oMFSf8EesuFBcn9hVpoqrpiS2WH0H50RKKL8hhKoxDfn/cNeD12L0Aj7kf6nNtexIllmkYG6lw=="
|
"integrity": "sha512-s/UJp9qxExL3DyQPT70kiuWeb3AdjbUZM+5lEIXn30I2DLcLYPOPXfsoWJODieQywq+3vPiLZeIdkoqjf6jcSw=="
|
||||||
},
|
},
|
||||||
"@types/estree": {
|
"@types/estree": {
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
@ -9799,9 +9818,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ionicons": {
|
"ionicons": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.3.tgz",
|
||||||
"integrity": "sha512-AyKfFaUKVoBz4eB8XkU7H1R5HFnVsgq5ijqSdbXC0lES9PDK/J6LUQz6XUJq0mVVQF5k9kczSPOLMW3mszG0mQ==",
|
"integrity": "sha512-kVOWER991EMqLiVShrCSWKMHkgHZP7XfVdyN6YPMuoO33W7pc5CPNVNfR8OMe/I8rYEbaunyBs6dXNYpR6gGZw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@stencil/core": "~2.16.0"
|
"@stencil/core": "~2.16.0"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ionic/angular",
|
"name": "@ionic/angular",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"description": "Angular specific wrappers for @ionic/core",
|
"description": "Angular specific wrappers for @ionic/core",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ionic",
|
"ionic",
|
||||||
@ -44,7 +44,7 @@
|
|||||||
"validate": "npm i && npm run lint && npm run test && npm run build"
|
"validate": "npm i && npm run lint && npm run test && npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ionic/core": "^6.2.3",
|
"@ionic/core": "^6.2.5",
|
||||||
"jsonc-parser": "^3.0.0",
|
"jsonc-parser": "^3.0.0",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,7 @@ import { RouteView, getUrl } from './stack-utils';
|
|||||||
selector: 'ion-router-outlet',
|
selector: 'ion-router-outlet',
|
||||||
exportAs: 'outlet',
|
exportAs: 'outlet',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['animated', 'animation', 'swipeGesture'],
|
inputs: ['animated', 'animation', 'mode', 'swipeGesture'],
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||||
export class IonRouterOutlet implements OnDestroy, OnInit {
|
export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||||
|
@ -3,6 +3,40 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [6.2.5](https://github.com/ionic-team/ionic/compare/v6.2.4...v6.2.5) (2022-08-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **action-sheet:** add aria-labelledby ([#25837](https://github.com/ionic-team/ionic/issues/25837)) ([5270151](https://github.com/ionic-team/ionic/commit/527015184e9413c1037277d3197bcaa33044c38c))
|
||||||
|
* **datetime:** next and previous buttons have correct labels ([#25845](https://github.com/ionic-team/ionic/issues/25845)) ([41e3387](https://github.com/ionic-team/ionic/commit/41e338730d32837fc9dd8a15477e37dea4cc76c9)), closes [#25844](https://github.com/ionic-team/ionic/issues/25844)
|
||||||
|
* **datetime:** only log out of bounds warning if value set ([#25835](https://github.com/ionic-team/ionic/issues/25835)) ([85af6ce](https://github.com/ionic-team/ionic/commit/85af6ce436890eb922d2ba32053fb8b8bc7fd4ff)), closes [#25833](https://github.com/ionic-team/ionic/issues/25833)
|
||||||
|
* **input:** clear button is not activated on swipe ([#25825](https://github.com/ionic-team/ionic/issues/25825)) ([ff71ad4](https://github.com/ionic-team/ionic/commit/ff71ad492d7671f8e550da7e08dbde30cb05ebf7)), closes [#24857](https://github.com/ionic-team/ionic/issues/24857)
|
||||||
|
* **modal:** handleBehavior can be used with controller ([#25821](https://github.com/ionic-team/ionic/issues/25821)) ([79ef1b5](https://github.com/ionic-team/ionic/commit/79ef1b57dc74fd856ed7c2904d7400d283cc081e)), closes [#25820](https://github.com/ionic-team/ionic/issues/25820)
|
||||||
|
* **searchbar:** clear button has focus indicator ([#25828](https://github.com/ionic-team/ionic/issues/25828)) ([373b4ff](https://github.com/ionic-team/ionic/commit/373b4ffe216ba584b92014cef501f64668e1f177))
|
||||||
|
* **searchbar:** keypress can activate clear button ([#25824](https://github.com/ionic-team/ionic/issues/25824)) ([c270756](https://github.com/ionic-team/ionic/commit/c270756356c7b23a1959ac5f4b8206a5cd1825c2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [6.2.4](https://github.com/ionic-team/ionic/compare/v6.2.3...v6.2.4) (2022-08-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **alert:** add default aria-label ([#25800](https://github.com/ionic-team/ionic/issues/25800)) ([d395a73](https://github.com/ionic-team/ionic/commit/d395a73cb6c419e6c0072746b8e4768cd5f78ef3))
|
||||||
|
* **alert:** use aria-labelledby and aria-describedby instead of aria-label ([#25805](https://github.com/ionic-team/ionic/issues/25805)) ([27318d7](https://github.com/ionic-team/ionic/commit/27318d75df60dfce1a90f23ba31ea2b6636ba42f))
|
||||||
|
* **breadcrumb:** separator is not announced by narrators ([#25796](https://github.com/ionic-team/ionic/issues/25796)) ([71fad38](https://github.com/ionic-team/ionic/commit/71fad3884bc55b266067efb346500c848b856946))
|
||||||
|
* **datetime:** close month/year picker when hidden ([#25789](https://github.com/ionic-team/ionic/issues/25789)) ([3b211b6](https://github.com/ionic-team/ionic/commit/3b211b60fd9a88be6e232f839ecc4be090181530)), closes [#25787](https://github.com/ionic-team/ionic/issues/25787)
|
||||||
|
* **modal:** role attribute can be customized ([#25804](https://github.com/ionic-team/ionic/issues/25804)) ([037d579](https://github.com/ionic-team/ionic/commit/037d579b2a3a660358f1e9c9b020c9510bb9c6b0))
|
||||||
|
* **refresher:** use componentOnReady utility for CE build ([#25783](https://github.com/ionic-team/ionic/issues/25783)) ([bd715a5](https://github.com/ionic-team/ionic/commit/bd715a52562f1f175d4bb6ea2dbfdd67a3e91db1)), closes [#25782](https://github.com/ionic-team/ionic/issues/25782)
|
||||||
|
* **select:** compareWith passes params in correct order ([#25764](https://github.com/ionic-team/ionic/issues/25764)) ([d631195](https://github.com/ionic-team/ionic/commit/d6311951243fd9b867ae5d4a7a08c8d341f8eb7a)), closes [#25759](https://github.com/ionic-team/ionic/issues/25759)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [6.2.3](https://github.com/ionic-team/ionic/compare/v6.2.2...v6.2.3) (2022-08-17)
|
## [6.2.3](https://github.com/ionic-team/ionic/compare/v6.2.2...v6.2.3) (2022-08-17)
|
||||||
|
|
||||||
|
|
||||||
|
18
core/package-lock.json
generated
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@ionic/core",
|
"name": "@ionic/core",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@ionic/core",
|
"name": "@ionic/core",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stencil/core": "^2.17.4",
|
"@stencil/core": "^2.17.4",
|
||||||
"ionicons": "^6.0.2",
|
"ionicons": "^6.0.3",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -6527,9 +6527,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ionicons": {
|
"node_modules/ionicons": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.3.tgz",
|
||||||
"integrity": "sha512-AyKfFaUKVoBz4eB8XkU7H1R5HFnVsgq5ijqSdbXC0lES9PDK/J6LUQz6XUJq0mVVQF5k9kczSPOLMW3mszG0mQ==",
|
"integrity": "sha512-kVOWER991EMqLiVShrCSWKMHkgHZP7XfVdyN6YPMuoO33W7pc5CPNVNfR8OMe/I8rYEbaunyBs6dXNYpR6gGZw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stencil/core": "~2.16.0"
|
"@stencil/core": "~2.16.0"
|
||||||
}
|
}
|
||||||
@ -19091,9 +19091,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ionicons": {
|
"ionicons": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.3.tgz",
|
||||||
"integrity": "sha512-AyKfFaUKVoBz4eB8XkU7H1R5HFnVsgq5ijqSdbXC0lES9PDK/J6LUQz6XUJq0mVVQF5k9kczSPOLMW3mszG0mQ==",
|
"integrity": "sha512-kVOWER991EMqLiVShrCSWKMHkgHZP7XfVdyN6YPMuoO33W7pc5CPNVNfR8OMe/I8rYEbaunyBs6dXNYpR6gGZw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@stencil/core": "~2.16.0"
|
"@stencil/core": "~2.16.0"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ionic/core",
|
"name": "@ionic/core",
|
||||||
"version": "6.2.3",
|
"version": "6.2.5",
|
||||||
"description": "Base components for Ionic",
|
"description": "Base components for Ionic",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ionic",
|
"ionic",
|
||||||
@ -32,7 +32,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stencil/core": "^2.17.4",
|
"@stencil/core": "^2.17.4",
|
||||||
"ionicons": "^6.0.2",
|
"ionicons": "^6.0.3",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
334
core/src/components.d.ts
vendored
@ -5,7 +5,7 @@
|
|||||||
* It contains typing information for all components that exist in this project.
|
* It contains typing information for all components that exist in this project.
|
||||||
*/
|
*/
|
||||||
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
||||||
import { AccordionGroupChangeEventDetail, ActionSheetAttributes, ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, BreadcrumbCollapsedClickEventDetail, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimePresentation, FrameworkDelegate, InputChangeEventDetail, ItemReorderEventDetail, LoadingAttributes, MenuChangeEventDetail, ModalAttributes, ModalBreakpointChangeEventDetail, ModalHandleBehavior, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerAttributes, PickerButton, PickerColumn, PopoverAttributes, PopoverSize, PositionAlign, PositionReference, PositionSide, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, TriggerAction, ViewController } from "./interface";
|
import { AccordionGroupChangeEventDetail, ActionSheetAttributes, ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, BreadcrumbCollapsedClickEventDetail, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimePresentation, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, LoadingAttributes, MenuChangeEventDetail, ModalAttributes, ModalBreakpointChangeEventDetail, ModalHandleBehavior, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerAttributes, PickerButton, PickerColumn, PopoverAttributes, PopoverSize, PositionAlign, PositionReference, PositionSide, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, TriggerAction, ViewController } from "./interface";
|
||||||
import { IonicSafeString } from "./utils/sanitization";
|
import { IonicSafeString } from "./utils/sanitization";
|
||||||
import { AlertAttributes } from "./components/alert/alert-interface";
|
import { AlertAttributes } from "./components/alert/alert-interface";
|
||||||
import { CounterFormatter } from "./components/item/item-interface";
|
import { CounterFormatter } from "./components/item/item-interface";
|
||||||
@ -2569,6 +2569,101 @@ export namespace Components {
|
|||||||
*/
|
*/
|
||||||
"animated": boolean;
|
"animated": boolean;
|
||||||
}
|
}
|
||||||
|
interface IonSlide {
|
||||||
|
}
|
||||||
|
interface IonSlides {
|
||||||
|
/**
|
||||||
|
* Get the index of the active slide.
|
||||||
|
*/
|
||||||
|
"getActiveIndex": () => Promise<number>;
|
||||||
|
/**
|
||||||
|
* Get the index of the previous slide.
|
||||||
|
*/
|
||||||
|
"getPreviousIndex": () => Promise<number>;
|
||||||
|
/**
|
||||||
|
* Get the Swiper instance. Use this to access the full Swiper API. See https://swiperjs.com/swiper-api for all API options.
|
||||||
|
*/
|
||||||
|
"getSwiper": () => Promise<any>;
|
||||||
|
/**
|
||||||
|
* Get whether or not the current slide is the first slide.
|
||||||
|
*/
|
||||||
|
"isBeginning": () => Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* Get whether or not the current slide is the last slide.
|
||||||
|
*/
|
||||||
|
"isEnd": () => Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* Get the total number of slides.
|
||||||
|
*/
|
||||||
|
"length": () => Promise<number>;
|
||||||
|
/**
|
||||||
|
* Lock or unlock the ability to slide to the next slide.
|
||||||
|
* @param lock If `true`, disable swiping to the next slide.
|
||||||
|
*/
|
||||||
|
"lockSwipeToNext": (lock: boolean) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Lock or unlock the ability to slide to the previous slide.
|
||||||
|
* @param lock If `true`, disable swiping to the previous slide.
|
||||||
|
*/
|
||||||
|
"lockSwipeToPrev": (lock: boolean) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Lock or unlock the ability to slide to the next or previous slide.
|
||||||
|
* @param lock If `true`, disable swiping to the next and previous slide.
|
||||||
|
*/
|
||||||
|
"lockSwipes": (lock: boolean) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* The mode determines which platform styles to use.
|
||||||
|
*/
|
||||||
|
"mode"?: "ios" | "md";
|
||||||
|
/**
|
||||||
|
* Options to pass to the swiper instance. See https://swiperjs.com/swiper-api for valid options
|
||||||
|
*/
|
||||||
|
"options": any;
|
||||||
|
/**
|
||||||
|
* If `true`, show the pagination.
|
||||||
|
*/
|
||||||
|
"pager": boolean;
|
||||||
|
/**
|
||||||
|
* If `true`, show the scrollbar.
|
||||||
|
*/
|
||||||
|
"scrollbar": boolean;
|
||||||
|
/**
|
||||||
|
* Transition to the next slide.
|
||||||
|
* @param speed The transition duration (in ms).
|
||||||
|
* @param runCallbacks If true, the transition will produce [Transition/SlideChange][Start/End] transition events.
|
||||||
|
*/
|
||||||
|
"slideNext": (speed?: number | undefined, runCallbacks?: boolean | undefined) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Transition to the previous slide.
|
||||||
|
* @param speed The transition duration (in ms).
|
||||||
|
* @param runCallbacks If true, the transition will produce the [Transition/SlideChange][Start/End] transition events.
|
||||||
|
*/
|
||||||
|
"slidePrev": (speed?: number | undefined, runCallbacks?: boolean | undefined) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Transition to the specified slide.
|
||||||
|
* @param index The index of the slide to transition to.
|
||||||
|
* @param speed The transition duration (in ms).
|
||||||
|
* @param runCallbacks If true, the transition will produce [Transition/SlideChange][Start/End] transition events.
|
||||||
|
*/
|
||||||
|
"slideTo": (index: number, speed?: number | undefined, runCallbacks?: boolean | undefined) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Start auto play.
|
||||||
|
*/
|
||||||
|
"startAutoplay": () => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Stop auto play.
|
||||||
|
*/
|
||||||
|
"stopAutoplay": () => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Update the underlying slider implementation. Call this if you've added or removed child slides.
|
||||||
|
*/
|
||||||
|
"update": () => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Force swiper to update its height (when autoHeight is enabled) for the duration equal to 'speed' parameter.
|
||||||
|
* @param speed The transition duration (in ms).
|
||||||
|
*/
|
||||||
|
"updateAutoHeight": (speed?: number | undefined) => Promise<void>;
|
||||||
|
}
|
||||||
interface IonSpinner {
|
interface IonSpinner {
|
||||||
/**
|
/**
|
||||||
* 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).
|
* 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).
|
||||||
@ -2929,6 +3024,73 @@ export namespace Components {
|
|||||||
*/
|
*/
|
||||||
"mode"?: "ios" | "md";
|
"mode"?: "ios" | "md";
|
||||||
}
|
}
|
||||||
|
interface IonVirtualScroll {
|
||||||
|
/**
|
||||||
|
* The approximate width of each footer template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxFooterHeight": number;
|
||||||
|
/**
|
||||||
|
* The approximate height of each header template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxHeaderHeight": number;
|
||||||
|
/**
|
||||||
|
* It is important to provide this if virtual item height will be significantly larger than the default The approximate height of each virtual item template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxItemHeight": number;
|
||||||
|
/**
|
||||||
|
* This method marks the tail the items array as dirty, so they can be re-rendered. It's equivalent to calling: ```js virtualScroll.checkRange(lastItemLen); ```
|
||||||
|
*/
|
||||||
|
"checkEnd": () => Promise<void>;
|
||||||
|
/**
|
||||||
|
* This method marks a subset of items as dirty, so they can be re-rendered. Items should be marked as dirty any time the content or their style changes. The subset of items to be updated can are specifying by an offset and a length.
|
||||||
|
*/
|
||||||
|
"checkRange": (offset: number, len?: number) => Promise<void>;
|
||||||
|
"domRender"?: DomRenderFn;
|
||||||
|
/**
|
||||||
|
* Section footers and the data used within its given template can be dynamically created by passing a function to `footerFn`. The logic within the footer function can decide if the footer template should be used, and what data to give to the footer template. The function must return `null` if a footer cell shouldn't be created.
|
||||||
|
*/
|
||||||
|
"footerFn"?: HeaderFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item footer within their height.
|
||||||
|
*/
|
||||||
|
"footerHeight"?: FooterHeightFn;
|
||||||
|
/**
|
||||||
|
* Section headers and the data used within its given template can be dynamically created by passing a function to `headerFn`. For example, a large list of contacts usually has dividers between each letter in the alphabet. App's can provide their own custom `headerFn` which is called with each record within the dataset. The logic within the header function can decide if the header template should be used, and what data to give to the header template. The function must return `null` if a header cell shouldn't be created.
|
||||||
|
*/
|
||||||
|
"headerFn"?: HeaderFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item header within their height.
|
||||||
|
*/
|
||||||
|
"headerHeight"?: HeaderHeightFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item within their height. When this function is provides, heavy optimizations and fast path can be taked by `ion-virtual-scroll` leading to massive performance improvements. This function allows to skip all DOM reads, which can be Doing so leads to massive performance
|
||||||
|
*/
|
||||||
|
"itemHeight"?: ItemHeightFn;
|
||||||
|
/**
|
||||||
|
* The data that builds the templates within the virtual scroll. It's important to note that when this data has changed, then the entire virtual scroll is reset, which is an expensive operation and should be avoided if possible.
|
||||||
|
*/
|
||||||
|
"items"?: any[];
|
||||||
|
/**
|
||||||
|
* NOTE: only Vanilla JS API.
|
||||||
|
*/
|
||||||
|
"nodeRender"?: ItemRenderFn;
|
||||||
|
/**
|
||||||
|
* Returns the position of the virtual item at the given index.
|
||||||
|
*/
|
||||||
|
"positionForItem": (index: number) => Promise<number>;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the footer to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderFooter"?: (item: any, index: number) => any;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the header to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderHeader"?: (item: any, index: number) => any;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the items to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderItem"?: (item: any, index: number) => any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export interface IonAccordionGroupCustomEvent<T> extends CustomEvent<T> {
|
export interface IonAccordionGroupCustomEvent<T> extends CustomEvent<T> {
|
||||||
detail: T;
|
detail: T;
|
||||||
@ -3082,6 +3244,10 @@ export interface IonSelectCustomEvent<T> extends CustomEvent<T> {
|
|||||||
detail: T;
|
detail: T;
|
||||||
target: HTMLIonSelectElement;
|
target: HTMLIonSelectElement;
|
||||||
}
|
}
|
||||||
|
export interface IonSlidesCustomEvent<T> extends CustomEvent<T> {
|
||||||
|
detail: T;
|
||||||
|
target: HTMLIonSlidesElement;
|
||||||
|
}
|
||||||
export interface IonSplitPaneCustomEvent<T> extends CustomEvent<T> {
|
export interface IonSplitPaneCustomEvent<T> extends CustomEvent<T> {
|
||||||
detail: T;
|
detail: T;
|
||||||
target: HTMLIonSplitPaneElement;
|
target: HTMLIonSplitPaneElement;
|
||||||
@ -3583,6 +3749,18 @@ declare global {
|
|||||||
prototype: HTMLIonSkeletonTextElement;
|
prototype: HTMLIonSkeletonTextElement;
|
||||||
new (): HTMLIonSkeletonTextElement;
|
new (): HTMLIonSkeletonTextElement;
|
||||||
};
|
};
|
||||||
|
interface HTMLIonSlideElement extends Components.IonSlide, HTMLStencilElement {
|
||||||
|
}
|
||||||
|
var HTMLIonSlideElement: {
|
||||||
|
prototype: HTMLIonSlideElement;
|
||||||
|
new (): HTMLIonSlideElement;
|
||||||
|
};
|
||||||
|
interface HTMLIonSlidesElement extends Components.IonSlides, HTMLStencilElement {
|
||||||
|
}
|
||||||
|
var HTMLIonSlidesElement: {
|
||||||
|
prototype: HTMLIonSlidesElement;
|
||||||
|
new (): HTMLIonSlidesElement;
|
||||||
|
};
|
||||||
interface HTMLIonSpinnerElement extends Components.IonSpinner, HTMLStencilElement {
|
interface HTMLIonSpinnerElement extends Components.IonSpinner, HTMLStencilElement {
|
||||||
}
|
}
|
||||||
var HTMLIonSpinnerElement: {
|
var HTMLIonSpinnerElement: {
|
||||||
@ -3661,6 +3839,12 @@ declare global {
|
|||||||
prototype: HTMLIonToolbarElement;
|
prototype: HTMLIonToolbarElement;
|
||||||
new (): HTMLIonToolbarElement;
|
new (): HTMLIonToolbarElement;
|
||||||
};
|
};
|
||||||
|
interface HTMLIonVirtualScrollElement extends Components.IonVirtualScroll, HTMLStencilElement {
|
||||||
|
}
|
||||||
|
var HTMLIonVirtualScrollElement: {
|
||||||
|
prototype: HTMLIonVirtualScrollElement;
|
||||||
|
new (): HTMLIonVirtualScrollElement;
|
||||||
|
};
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ion-accordion": HTMLIonAccordionElement;
|
"ion-accordion": HTMLIonAccordionElement;
|
||||||
"ion-accordion-group": HTMLIonAccordionGroupElement;
|
"ion-accordion-group": HTMLIonAccordionGroupElement;
|
||||||
@ -3740,6 +3924,8 @@ declare global {
|
|||||||
"ion-select-option": HTMLIonSelectOptionElement;
|
"ion-select-option": HTMLIonSelectOptionElement;
|
||||||
"ion-select-popover": HTMLIonSelectPopoverElement;
|
"ion-select-popover": HTMLIonSelectPopoverElement;
|
||||||
"ion-skeleton-text": HTMLIonSkeletonTextElement;
|
"ion-skeleton-text": HTMLIonSkeletonTextElement;
|
||||||
|
"ion-slide": HTMLIonSlideElement;
|
||||||
|
"ion-slides": HTMLIonSlidesElement;
|
||||||
"ion-spinner": HTMLIonSpinnerElement;
|
"ion-spinner": HTMLIonSpinnerElement;
|
||||||
"ion-split-pane": HTMLIonSplitPaneElement;
|
"ion-split-pane": HTMLIonSplitPaneElement;
|
||||||
"ion-tab": HTMLIonTabElement;
|
"ion-tab": HTMLIonTabElement;
|
||||||
@ -3753,6 +3939,7 @@ declare global {
|
|||||||
"ion-toast": HTMLIonToastElement;
|
"ion-toast": HTMLIonToastElement;
|
||||||
"ion-toggle": HTMLIonToggleElement;
|
"ion-toggle": HTMLIonToggleElement;
|
||||||
"ion-toolbar": HTMLIonToolbarElement;
|
"ion-toolbar": HTMLIonToolbarElement;
|
||||||
|
"ion-virtual-scroll": HTMLIonVirtualScrollElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
declare namespace LocalJSX {
|
declare namespace LocalJSX {
|
||||||
@ -6363,6 +6550,90 @@ declare namespace LocalJSX {
|
|||||||
*/
|
*/
|
||||||
"animated"?: boolean;
|
"animated"?: boolean;
|
||||||
}
|
}
|
||||||
|
interface IonSlide {
|
||||||
|
}
|
||||||
|
interface IonSlides {
|
||||||
|
/**
|
||||||
|
* The mode determines which platform styles to use.
|
||||||
|
*/
|
||||||
|
"mode"?: "ios" | "md";
|
||||||
|
/**
|
||||||
|
* Emitted after the active slide has changed.
|
||||||
|
*/
|
||||||
|
"onIonSlideDidChange"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the user double taps on the slide's container.
|
||||||
|
*/
|
||||||
|
"onIonSlideDoubleTap"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the slider is actively being moved.
|
||||||
|
*/
|
||||||
|
"onIonSlideDrag"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the next slide has ended.
|
||||||
|
*/
|
||||||
|
"onIonSlideNextEnd"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the next slide has started.
|
||||||
|
*/
|
||||||
|
"onIonSlideNextStart"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the previous slide has ended.
|
||||||
|
*/
|
||||||
|
"onIonSlidePrevEnd"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the previous slide has started.
|
||||||
|
*/
|
||||||
|
"onIonSlidePrevStart"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the slider is at the last slide.
|
||||||
|
*/
|
||||||
|
"onIonSlideReachEnd"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the slider is at its initial position.
|
||||||
|
*/
|
||||||
|
"onIonSlideReachStart"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the user taps/clicks on the slide's container.
|
||||||
|
*/
|
||||||
|
"onIonSlideTap"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the user releases the touch.
|
||||||
|
*/
|
||||||
|
"onIonSlideTouchEnd"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the user first touches the slider.
|
||||||
|
*/
|
||||||
|
"onIonSlideTouchStart"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the slide transition has ended.
|
||||||
|
*/
|
||||||
|
"onIonSlideTransitionEnd"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted when the slide transition has started.
|
||||||
|
*/
|
||||||
|
"onIonSlideTransitionStart"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted before the active slide has changed.
|
||||||
|
*/
|
||||||
|
"onIonSlideWillChange"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Emitted after Swiper initialization
|
||||||
|
*/
|
||||||
|
"onIonSlidesDidLoad"?: (event: IonSlidesCustomEvent<void>) => void;
|
||||||
|
/**
|
||||||
|
* Options to pass to the swiper instance. See https://swiperjs.com/swiper-api for valid options
|
||||||
|
*/
|
||||||
|
"options"?: any;
|
||||||
|
/**
|
||||||
|
* If `true`, show the pagination.
|
||||||
|
*/
|
||||||
|
"pager"?: boolean;
|
||||||
|
/**
|
||||||
|
* If `true`, show the scrollbar.
|
||||||
|
*/
|
||||||
|
"scrollbar"?: boolean;
|
||||||
|
}
|
||||||
interface IonSpinner {
|
interface IonSpinner {
|
||||||
/**
|
/**
|
||||||
* 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).
|
* 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).
|
||||||
@ -6754,6 +7025,61 @@ declare namespace LocalJSX {
|
|||||||
*/
|
*/
|
||||||
"mode"?: "ios" | "md";
|
"mode"?: "ios" | "md";
|
||||||
}
|
}
|
||||||
|
interface IonVirtualScroll {
|
||||||
|
/**
|
||||||
|
* The approximate width of each footer template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxFooterHeight"?: number;
|
||||||
|
/**
|
||||||
|
* The approximate height of each header template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxHeaderHeight"?: number;
|
||||||
|
/**
|
||||||
|
* It is important to provide this if virtual item height will be significantly larger than the default The approximate height of each virtual item template's cell. This dimension is used to help determine how many cells should be created when initialized, and to help calculate the height of the scrollable area. This height value can only use `px` units. Note that the actual rendered size of each cell comes from the app's CSS, whereas this approximation is used to help calculate initial dimensions before the item has been rendered.
|
||||||
|
*/
|
||||||
|
"approxItemHeight"?: number;
|
||||||
|
"domRender"?: DomRenderFn;
|
||||||
|
/**
|
||||||
|
* Section footers and the data used within its given template can be dynamically created by passing a function to `footerFn`. The logic within the footer function can decide if the footer template should be used, and what data to give to the footer template. The function must return `null` if a footer cell shouldn't be created.
|
||||||
|
*/
|
||||||
|
"footerFn"?: HeaderFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item footer within their height.
|
||||||
|
*/
|
||||||
|
"footerHeight"?: FooterHeightFn;
|
||||||
|
/**
|
||||||
|
* Section headers and the data used within its given template can be dynamically created by passing a function to `headerFn`. For example, a large list of contacts usually has dividers between each letter in the alphabet. App's can provide their own custom `headerFn` which is called with each record within the dataset. The logic within the header function can decide if the header template should be used, and what data to give to the header template. The function must return `null` if a header cell shouldn't be created.
|
||||||
|
*/
|
||||||
|
"headerFn"?: HeaderFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item header within their height.
|
||||||
|
*/
|
||||||
|
"headerHeight"?: HeaderHeightFn;
|
||||||
|
/**
|
||||||
|
* An optional function that maps each item within their height. When this function is provides, heavy optimizations and fast path can be taked by `ion-virtual-scroll` leading to massive performance improvements. This function allows to skip all DOM reads, which can be Doing so leads to massive performance
|
||||||
|
*/
|
||||||
|
"itemHeight"?: ItemHeightFn;
|
||||||
|
/**
|
||||||
|
* The data that builds the templates within the virtual scroll. It's important to note that when this data has changed, then the entire virtual scroll is reset, which is an expensive operation and should be avoided if possible.
|
||||||
|
*/
|
||||||
|
"items"?: any[];
|
||||||
|
/**
|
||||||
|
* NOTE: only Vanilla JS API.
|
||||||
|
*/
|
||||||
|
"nodeRender"?: ItemRenderFn;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the footer to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderFooter"?: (item: any, index: number) => any;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the header to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderHeader"?: (item: any, index: number) => any;
|
||||||
|
/**
|
||||||
|
* NOTE: only JSX API for stencil. Provide a render function for the items to be rendered. Returns a JSX virtual-dom.
|
||||||
|
*/
|
||||||
|
"renderItem"?: (item: any, index: number) => any;
|
||||||
|
}
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
"ion-accordion": IonAccordion;
|
"ion-accordion": IonAccordion;
|
||||||
"ion-accordion-group": IonAccordionGroup;
|
"ion-accordion-group": IonAccordionGroup;
|
||||||
@ -6833,6 +7159,8 @@ declare namespace LocalJSX {
|
|||||||
"ion-select-option": IonSelectOption;
|
"ion-select-option": IonSelectOption;
|
||||||
"ion-select-popover": IonSelectPopover;
|
"ion-select-popover": IonSelectPopover;
|
||||||
"ion-skeleton-text": IonSkeletonText;
|
"ion-skeleton-text": IonSkeletonText;
|
||||||
|
"ion-slide": IonSlide;
|
||||||
|
"ion-slides": IonSlides;
|
||||||
"ion-spinner": IonSpinner;
|
"ion-spinner": IonSpinner;
|
||||||
"ion-split-pane": IonSplitPane;
|
"ion-split-pane": IonSplitPane;
|
||||||
"ion-tab": IonTab;
|
"ion-tab": IonTab;
|
||||||
@ -6846,6 +7174,7 @@ declare namespace LocalJSX {
|
|||||||
"ion-toast": IonToast;
|
"ion-toast": IonToast;
|
||||||
"ion-toggle": IonToggle;
|
"ion-toggle": IonToggle;
|
||||||
"ion-toolbar": IonToolbar;
|
"ion-toolbar": IonToolbar;
|
||||||
|
"ion-virtual-scroll": IonVirtualScroll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { LocalJSX as JSX };
|
export { LocalJSX as JSX };
|
||||||
@ -6930,6 +7259,8 @@ declare module "@stencil/core" {
|
|||||||
"ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes<HTMLIonSelectOptionElement>;
|
"ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes<HTMLIonSelectOptionElement>;
|
||||||
"ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes<HTMLIonSelectPopoverElement>;
|
"ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes<HTMLIonSelectPopoverElement>;
|
||||||
"ion-skeleton-text": LocalJSX.IonSkeletonText & JSXBase.HTMLAttributes<HTMLIonSkeletonTextElement>;
|
"ion-skeleton-text": LocalJSX.IonSkeletonText & JSXBase.HTMLAttributes<HTMLIonSkeletonTextElement>;
|
||||||
|
"ion-slide": LocalJSX.IonSlide & JSXBase.HTMLAttributes<HTMLIonSlideElement>;
|
||||||
|
"ion-slides": LocalJSX.IonSlides & JSXBase.HTMLAttributes<HTMLIonSlidesElement>;
|
||||||
"ion-spinner": LocalJSX.IonSpinner & JSXBase.HTMLAttributes<HTMLIonSpinnerElement>;
|
"ion-spinner": LocalJSX.IonSpinner & JSXBase.HTMLAttributes<HTMLIonSpinnerElement>;
|
||||||
"ion-split-pane": LocalJSX.IonSplitPane & JSXBase.HTMLAttributes<HTMLIonSplitPaneElement>;
|
"ion-split-pane": LocalJSX.IonSplitPane & JSXBase.HTMLAttributes<HTMLIonSplitPaneElement>;
|
||||||
"ion-tab": LocalJSX.IonTab & JSXBase.HTMLAttributes<HTMLIonTabElement>;
|
"ion-tab": LocalJSX.IonTab & JSXBase.HTMLAttributes<HTMLIonTabElement>;
|
||||||
@ -6943,6 +7274,7 @@ declare module "@stencil/core" {
|
|||||||
"ion-toast": LocalJSX.IonToast & JSXBase.HTMLAttributes<HTMLIonToastElement>;
|
"ion-toast": LocalJSX.IonToast & JSXBase.HTMLAttributes<HTMLIonToastElement>;
|
||||||
"ion-toggle": LocalJSX.IonToggle & JSXBase.HTMLAttributes<HTMLIonToggleElement>;
|
"ion-toggle": LocalJSX.IonToggle & JSXBase.HTMLAttributes<HTMLIonToggleElement>;
|
||||||
"ion-toolbar": LocalJSX.IonToolbar & JSXBase.HTMLAttributes<HTMLIonToolbarElement>;
|
"ion-toolbar": LocalJSX.IonToolbar & JSXBase.HTMLAttributes<HTMLIonToolbarElement>;
|
||||||
|
"ion-virtual-scroll": LocalJSX.IonVirtualScroll & JSXBase.HTMLAttributes<HTMLIonVirtualScrollElement>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,16 +239,18 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { htmlAttributes } = this;
|
const { header, htmlAttributes, overlayIndex } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const allButtons = this.getButtons();
|
const allButtons = this.getButtons();
|
||||||
const cancelButton = allButtons.find((b) => b.role === 'cancel');
|
const cancelButton = allButtons.find((b) => b.role === 'cancel');
|
||||||
const buttons = allButtons.filter((b) => b.role !== 'cancel');
|
const buttons = allButtons.filter((b) => b.role !== 'cancel');
|
||||||
|
const headerID = `action-sheet-${overlayIndex}-header`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
|
aria-labelledby={header !== undefined ? headerID : null}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
{...(htmlAttributes as any)}
|
{...(htmlAttributes as any)}
|
||||||
style={{
|
style={{
|
||||||
@ -256,7 +258,6 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
|||||||
}}
|
}}
|
||||||
class={{
|
class={{
|
||||||
[mode]: true,
|
[mode]: true,
|
||||||
|
|
||||||
...getClassMap(this.cssClass),
|
...getClassMap(this.cssClass),
|
||||||
'overlay-hidden': true,
|
'overlay-hidden': true,
|
||||||
'action-sheet-translucent': this.translucent,
|
'action-sheet-translucent': this.translucent,
|
||||||
@ -268,17 +269,18 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
|||||||
|
|
||||||
<div tabindex="0"></div>
|
<div tabindex="0"></div>
|
||||||
|
|
||||||
<div class="action-sheet-wrapper ion-overlay-wrapper" role="dialog" ref={(el) => (this.wrapperEl = el)}>
|
<div class="action-sheet-wrapper ion-overlay-wrapper" ref={(el) => (this.wrapperEl = el)}>
|
||||||
<div class="action-sheet-container">
|
<div class="action-sheet-container">
|
||||||
<div class="action-sheet-group" ref={(el) => (this.groupEl = el)}>
|
<div class="action-sheet-group" ref={(el) => (this.groupEl = el)}>
|
||||||
{this.header !== undefined && (
|
{header !== undefined && (
|
||||||
<div
|
<div
|
||||||
|
id={headerID}
|
||||||
class={{
|
class={{
|
||||||
'action-sheet-title': true,
|
'action-sheet-title': true,
|
||||||
'action-sheet-has-sub-title': this.subHeader !== undefined,
|
'action-sheet-has-sub-title': this.subHeader !== undefined,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{this.header}
|
{header}
|
||||||
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
|
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
import AxeBuilder from '@axe-core/playwright';
|
||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import type { E2EPage } from '@utils/test/playwright';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
const testAria = async (page: E2EPage, buttonID: string, expectedAriaLabelledBy: string | null) => {
|
||||||
|
const didPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||||
|
const button = page.locator(`#${buttonID}`);
|
||||||
|
|
||||||
|
await button.click();
|
||||||
|
await didPresent.next();
|
||||||
|
|
||||||
|
const alert = page.locator('ion-action-sheet');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* expect().toHaveAttribute() can't check for a null value, so grab and check
|
||||||
|
* the value manually instead.
|
||||||
|
*/
|
||||||
|
const ariaLabelledBy = await alert.getAttribute('aria-labelledby');
|
||||||
|
|
||||||
|
expect(ariaLabelledBy).toBe(expectedAriaLabelledBy);
|
||||||
|
};
|
||||||
|
|
||||||
|
test.describe('action-sheet: a11y', () => {
|
||||||
|
test.beforeEach(async ({ page, skip }) => {
|
||||||
|
skip.rtl();
|
||||||
|
await page.goto(`/src/components/action-sheet/test/a11y`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not have accessibility violations when header is defined', async ({ page }) => {
|
||||||
|
const button = page.locator('#bothHeaders');
|
||||||
|
const didPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||||
|
|
||||||
|
await button.click();
|
||||||
|
await didPresent.next();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* action-sheet overlays the entire screen, so
|
||||||
|
* Axe will be unable to verify color contrast
|
||||||
|
* on elements under the backdrop.
|
||||||
|
*/
|
||||||
|
const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze();
|
||||||
|
expect(results.violations).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should have aria-labelledby when header is set', async ({ page }) => {
|
||||||
|
await testAria(page, 'bothHeaders', 'action-sheet-1-header');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not have aria-labelledby when header is not set', async ({ page }) => {
|
||||||
|
await testAria(page, 'noHeaders', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should allow for manually specifying aria attributes', async ({ page }) => {
|
||||||
|
await testAria(page, 'customAria', 'Custom title');
|
||||||
|
});
|
||||||
|
});
|
68
core/src/components/action-sheet/test/a11y/index.html
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Action Sheet - A11y</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||||
|
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||||
|
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||||
|
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||||
|
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||||
|
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||||
|
</head>
|
||||||
|
<script type="module">
|
||||||
|
import { actionSheetController } from '../../../../dist/ionic/index.esm.js';
|
||||||
|
window.actionSheetController = actionSheetController;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main class="ion-padding">
|
||||||
|
<h1>Action Sheet - A11y</h1>
|
||||||
|
|
||||||
|
<ion-button id="bothHeaders" expand="block" onclick="presentBothHeaders()">Both Headers</ion-button>
|
||||||
|
<ion-button id="subHeaderOnly" expand="block" onclick="presentSubHeaderOnly()">Subheader Only</ion-button>
|
||||||
|
<ion-button id="noHeaders" expand="block" onclick="presentNoHeaders()">No Headers</ion-button>
|
||||||
|
<ion-button id="customAria" expand="block" onclick="presentCustomAria()">Custom Aria</ion-button>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function openActionSheet(opts) {
|
||||||
|
const actionSheet = await actionSheetController.create(opts);
|
||||||
|
await actionSheet.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentBothHeaders() {
|
||||||
|
openActionSheet({
|
||||||
|
header: 'Header',
|
||||||
|
subHeader: 'Subtitle',
|
||||||
|
buttons: ['Confirm'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentSubHeaderOnly() {
|
||||||
|
openActionSheet({
|
||||||
|
subHeader: 'Subtitle',
|
||||||
|
buttons: ['Confirm'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentNoHeaders() {
|
||||||
|
openActionSheet({
|
||||||
|
buttons: ['Confirm'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentCustomAria() {
|
||||||
|
openActionSheet({
|
||||||
|
header: 'Header',
|
||||||
|
subHeader: 'Subtitle',
|
||||||
|
buttons: ['Confirm'],
|
||||||
|
htmlAttributes: {
|
||||||
|
'aria-labelledby': 'Custom title',
|
||||||
|
'aria-describedby': 'Custom description',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -578,20 +578,26 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { overlayIndex, header, subHeader, htmlAttributes } = this;
|
const { overlayIndex, header, subHeader, message, htmlAttributes } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const hdrId = `alert-${overlayIndex}-hdr`;
|
const hdrId = `alert-${overlayIndex}-hdr`;
|
||||||
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
|
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
|
||||||
const msgId = `alert-${overlayIndex}-msg`;
|
const msgId = `alert-${overlayIndex}-msg`;
|
||||||
const role = this.inputs.length > 0 || this.buttons.length > 0 ? 'alertdialog' : 'alert';
|
const role = this.inputs.length > 0 || this.buttons.length > 0 ? 'alertdialog' : 'alert';
|
||||||
const defaultAriaLabel = header || subHeader || 'Alert';
|
|
||||||
|
/**
|
||||||
|
* If the header is defined, use that. Otherwise, fall back to the subHeader.
|
||||||
|
* If neither is defined, don't set aria-labelledby.
|
||||||
|
*/
|
||||||
|
const ariaLabelledBy = header ? hdrId : subHeader ? subHdrId : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
role={role}
|
role={role}
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
|
aria-labelledby={ariaLabelledBy}
|
||||||
|
aria-describedby={message ? msgId : null}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-label={defaultAriaLabel}
|
|
||||||
{...(htmlAttributes as any)}
|
{...(htmlAttributes as any)}
|
||||||
style={{
|
style={{
|
||||||
zIndex: `${20000 + overlayIndex}`,
|
zIndex: `${20000 + overlayIndex}`,
|
||||||
@ -623,7 +629,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id={msgId} class="alert-message" innerHTML={sanitizeDOMString(this.message)}></div>
|
<div id={msgId} class="alert-message" innerHTML={sanitizeDOMString(message)}></div>
|
||||||
|
|
||||||
{this.renderAlertInputs()}
|
{this.renderAlertInputs()}
|
||||||
{this.renderAlertButtons()}
|
{this.renderAlertButtons()}
|
||||||
|
@ -3,12 +3,29 @@ import { expect } from '@playwright/test';
|
|||||||
import type { E2EPage } from '@utils/test/playwright';
|
import type { E2EPage } from '@utils/test/playwright';
|
||||||
import { test } from '@utils/test/playwright';
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
const testAriaLabel = async (page: E2EPage, buttonID: string, expectedAriaLabel: string) => {
|
const testAria = async (
|
||||||
|
page: E2EPage,
|
||||||
|
buttonID: string,
|
||||||
|
expectedAriaLabelledBy: string | null,
|
||||||
|
expectedAriaDescribedBy: string | null
|
||||||
|
) => {
|
||||||
|
const didPresent = await page.spyOnEvent('ionAlertDidPresent');
|
||||||
const button = page.locator(`#${buttonID}`);
|
const button = page.locator(`#${buttonID}`);
|
||||||
|
|
||||||
await button.click();
|
await button.click();
|
||||||
|
await didPresent.next();
|
||||||
|
|
||||||
const alert = page.locator('ion-alert');
|
const alert = page.locator('ion-alert');
|
||||||
await expect(alert).toHaveAttribute('aria-label', expectedAriaLabel);
|
|
||||||
|
/**
|
||||||
|
* expect().toHaveAttribute() can't check for a null value, so grab and check
|
||||||
|
* the values manually instead.
|
||||||
|
*/
|
||||||
|
const ariaLabelledBy = await alert.getAttribute('aria-labelledby');
|
||||||
|
const ariaDescribedBy = await alert.getAttribute('aria-describedby');
|
||||||
|
|
||||||
|
expect(ariaLabelledBy).toBe(expectedAriaLabelledBy);
|
||||||
|
expect(ariaDescribedBy).toBe(expectedAriaDescribedBy);
|
||||||
};
|
};
|
||||||
|
|
||||||
test.describe('alert: a11y', () => {
|
test.describe('alert: a11y', () => {
|
||||||
@ -17,27 +34,27 @@ test.describe('alert: a11y', () => {
|
|||||||
await page.goto(`/src/components/alert/test/a11y`);
|
await page.goto(`/src/components/alert/test/a11y`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not have accessibility violations', async ({ page }) => {
|
test('should not have accessibility violations when header and message are defined', async ({ page }) => {
|
||||||
const button = page.locator('#customHeader');
|
const button = page.locator('#bothHeaders');
|
||||||
await button.click();
|
await button.click();
|
||||||
|
|
||||||
const results = await new AxeBuilder({ page }).analyze();
|
const results = await new AxeBuilder({ page }).analyze();
|
||||||
expect(results.violations).toEqual([]);
|
expect(results.violations).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should have fallback aria-label when no header or subheader is specified', async ({ page }) => {
|
test('should have aria-labelledby when header is set', async ({ page }) => {
|
||||||
await testAriaLabel(page, 'noHeader', 'Alert');
|
await testAria(page, 'noMessage', 'alert-1-hdr', null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should inherit aria-label from header', async ({ page }) => {
|
test('should have aria-describedby when message is set', async ({ page }) => {
|
||||||
await testAriaLabel(page, 'customHeader', 'Header');
|
await testAria(page, 'noHeaders', null, 'alert-1-msg');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should inherit aria-label from subheader if no header is specified', async ({ page }) => {
|
test('should fall back to subHeader for aria-labelledby if header is not defined', async ({ page }) => {
|
||||||
await testAriaLabel(page, 'subHeaderOnly', 'Subtitle');
|
await testAria(page, 'subHeaderOnly', 'alert-1-sub-hdr', 'alert-1-msg');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should allow for manually specifying aria-label', async ({ page }) => {
|
test('should allow for manually specifying aria attributes', async ({ page }) => {
|
||||||
await testAriaLabel(page, 'customAriaLabel', 'Custom alert');
|
await testAria(page, 'customAria', 'Custom title', 'Custom description');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,14 +19,11 @@
|
|||||||
<main class="ion-padding">
|
<main class="ion-padding">
|
||||||
<h1>Alert - A11y</h1>
|
<h1>Alert - A11y</h1>
|
||||||
|
|
||||||
<ion-button id="noHeader" expand="block" onclick="presentNoHeader()">Alert With No Header</ion-button>
|
<ion-button id="bothHeaders" expand="block" onclick="presentBothHeaders()">Both Headers</ion-button>
|
||||||
<ion-button id="customHeader" expand="block" onclick="presentCustomHeader()">Alert With Custom Header</ion-button>
|
<ion-button id="subHeaderOnly" expand="block" onclick="presentSubHeaderOnly()">Subheader Only</ion-button>
|
||||||
<ion-button id="subHeaderOnly" expand="block" onclick="presentSubHeaderOnly()"
|
<ion-button id="noHeaders" expand="block" onclick="presentNoHeaders()">No Headers</ion-button>
|
||||||
>Alert With Subheader Only</ion-button
|
<ion-button id="noMessage" expand="block" onclick="presentNoMessage()">No Message</ion-button>
|
||||||
>
|
<ion-button id="customAria" expand="block" onclick="presentCustomAria()">Custom Aria</ion-button>
|
||||||
<ion-button id="customAriaLabel" expand="block" onclick="presentCustomAriaLabel()"
|
|
||||||
>Alert With Custom Aria Label</ion-button
|
|
||||||
>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -35,14 +32,7 @@
|
|||||||
await alert.present();
|
await alert.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
function presentNoHeader() {
|
function presentBothHeaders() {
|
||||||
openAlert({
|
|
||||||
message: 'This is an alert message.',
|
|
||||||
buttons: ['OK'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function presentCustomHeader() {
|
|
||||||
openAlert({
|
openAlert({
|
||||||
header: 'Header',
|
header: 'Header',
|
||||||
subHeader: 'Subtitle',
|
subHeader: 'Subtitle',
|
||||||
@ -59,14 +49,30 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function presentCustomAriaLabel() {
|
function presentNoHeaders() {
|
||||||
|
openAlert({
|
||||||
|
message: 'This is an alert message.',
|
||||||
|
buttons: ['OK'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentNoMessage() {
|
||||||
openAlert({
|
openAlert({
|
||||||
header: 'Header',
|
header: 'Header',
|
||||||
subHeader: 'Subtitle',
|
subHeader: 'Subtitle',
|
||||||
message: 'This is an alert message with a custom aria-label.',
|
buttons: ['OK'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentCustomAria() {
|
||||||
|
openAlert({
|
||||||
|
header: 'Header',
|
||||||
|
subHeader: 'Subtitle',
|
||||||
|
message: 'This is an alert message with custom aria attributes.',
|
||||||
buttons: ['OK'],
|
buttons: ['OK'],
|
||||||
htmlAttributes: {
|
htmlAttributes: {
|
||||||
'aria-label': 'Custom alert',
|
'aria-labelledby': 'Custom title',
|
||||||
|
'aria-describedby': 'Custom description',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
90
core/src/components/alert/test/basic/alert.e2e.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import type { E2EPage } from '@utils/test/playwright';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
const openAlert = async (page: E2EPage, buttonID: string) => {
|
||||||
|
const didPresent = await page.spyOnEvent('ionAlertDidPresent');
|
||||||
|
|
||||||
|
await page.click(`#${buttonID}`);
|
||||||
|
await didPresent.next();
|
||||||
|
|
||||||
|
return page.locator('ion-alert');
|
||||||
|
};
|
||||||
|
|
||||||
|
const testAlert = async (page: E2EPage, buttonID: string) => {
|
||||||
|
await page.goto(`/src/components/alert/test/basic`);
|
||||||
|
|
||||||
|
const didDismiss = await page.spyOnEvent('ionAlertDidDismiss');
|
||||||
|
const alert = await openAlert(page, buttonID);
|
||||||
|
|
||||||
|
await expect(alert).toBeVisible();
|
||||||
|
expect(await alert.screenshot()).toMatchSnapshot(`alert-${buttonID}-${page.getSnapshotSettings()}.png`);
|
||||||
|
|
||||||
|
await alert.evaluate((el: HTMLIonAlertElement) => el.dismiss());
|
||||||
|
await didDismiss.next();
|
||||||
|
|
||||||
|
await expect(alert).toHaveCount(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
test.describe('alert: basic', () => {
|
||||||
|
test('focus trap should work correctly', async ({ page, skip, browserName }) => {
|
||||||
|
skip.rtl();
|
||||||
|
await page.goto(`/src/components/alert/test/basic`);
|
||||||
|
|
||||||
|
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
||||||
|
|
||||||
|
const alert = await openAlert(page, 'multipleButtons');
|
||||||
|
const alertBtns = alert.locator('button');
|
||||||
|
|
||||||
|
await page.keyboard.press(tabKey);
|
||||||
|
await expect(alertBtns.nth(0)).toBeFocused();
|
||||||
|
|
||||||
|
await page.keyboard.press(`Shift+${tabKey}`);
|
||||||
|
await expect(alertBtns.nth(2)).toBeFocused();
|
||||||
|
|
||||||
|
await page.keyboard.press(tabKey);
|
||||||
|
await expect(alertBtns.nth(0)).toBeFocused();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should set custom attributes', async ({ page, skip }) => {
|
||||||
|
skip.rtl();
|
||||||
|
await page.goto(`/src/components/alert/test/basic`);
|
||||||
|
|
||||||
|
const alert = await openAlert(page, 'basic');
|
||||||
|
expect(alert).toHaveAttribute('data-testid', 'basic-alert');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('should not have visual regressions', () => {
|
||||||
|
test('header, subheader, message', async ({ page }) => {
|
||||||
|
await testAlert(page, 'basic');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('long message', async ({ page }) => {
|
||||||
|
await testAlert(page, 'longMessage');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('more than two buttons', async ({ page }) => {
|
||||||
|
await testAlert(page, 'multipleButtons');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no message', async ({ page }) => {
|
||||||
|
await testAlert(page, 'noMessage');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('two buttons', async ({ page }) => {
|
||||||
|
await testAlert(page, 'confirm');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('form prompt', async ({ page }) => {
|
||||||
|
await testAlert(page, 'prompt');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('radios', async ({ page }) => {
|
||||||
|
await testAlert(page, 'radio');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('checkboxes', async ({ page }) => {
|
||||||
|
await testAlert(page, 'checkbox');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 269 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 269 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 244 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 243 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 41 KiB |