Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d41a7a6f | ||
|
|
e09d5c82b3 | ||
|
|
6dfedec4c0 | ||
|
|
1a4494199e | ||
|
|
2220d83d32 | ||
|
|
adf220b681 | ||
|
|
e64015a609 | ||
|
|
3d9871a77f | ||
|
|
e91fee4f2d | ||
|
|
b315b0cb29 | ||
|
|
7b6c330f17 | ||
|
|
b3cd49bf22 | ||
|
|
6c36cef241 | ||
|
|
4d6edee89c | ||
|
|
6945adc3cc | ||
|
|
90a7e70a1c | ||
|
|
0f5d1c02d2 | ||
|
|
4b79bbef7d | ||
|
|
ac7631a324 | ||
|
|
b5cb828861 | ||
|
|
101ad5402f | ||
|
|
de35fa8b94 | ||
|
|
c766528a17 | ||
|
|
9b3cf9fbc2 | ||
|
|
ee5da7a747 | ||
|
|
c4bfc783e0 | ||
|
|
0137e732ce | ||
|
|
88ecb29e39 | ||
|
|
f726c35868 | ||
|
|
4a9d84ecbd | ||
|
|
f08759c2b8 | ||
|
|
2053bc77a6 | ||
|
|
02e05bd7cb | ||
|
|
fa387cb2a2 | ||
|
|
8ab116150c | ||
|
|
8c9182c52f | ||
|
|
c0a8e7a95d | ||
|
|
0c5a2967d8 | ||
|
|
6ebb3c4e38 | ||
|
|
cdcb6decbd | ||
|
|
652ea169b7 | ||
|
|
42c09a7ea1 | ||
|
|
c23be1befd | ||
|
|
a2923aaeb3 | ||
|
|
eeab96de55 | ||
|
|
ca0923812a | ||
|
|
1be956bd18 | ||
|
|
8ad66c03d7 |
66
.github/CODEOWNERS
vendored
@@ -13,73 +13,7 @@
|
||||
|
||||
* @ionic-team/framework
|
||||
|
||||
# Frameworks
|
||||
|
||||
## Angular
|
||||
|
||||
/packages/angular/ @sean-perkins @thetaPC
|
||||
/packages/angular-server @sean-perkins @thetaPC
|
||||
/packages/angular/test @thetaPC
|
||||
|
||||
## React
|
||||
|
||||
/packages/react/ @amandaejohnston
|
||||
/packages/react-router @amandaejohnston
|
||||
/packages/react/test-app/
|
||||
/packages/react-router/test-app/
|
||||
|
||||
## Vue
|
||||
|
||||
/packages/vue/ @liamdebeasi @thetaPC
|
||||
/packages/vue-router/ @liamdebeasi @thetaPC
|
||||
/packages/vue/test/ @thetaPC
|
||||
/packages/vue-router/__tests__ @thetaPC
|
||||
|
||||
# Components
|
||||
|
||||
/core/src/components/accordion/ @liamdebeasi
|
||||
/core/src/components/accordion-group/ @liamdebeasi
|
||||
|
||||
/core/src/components/checkbox/ @amandaejohnston
|
||||
|
||||
/core/src/components/datetime/ @liamdebeasi @amandaejohnston @sean-perkins
|
||||
/core/src/components/datetime-button/ @liamdebeasi
|
||||
|
||||
/core/src/components/item/ @brandyscarney
|
||||
|
||||
/core/src/components/menu/ @amandaejohnston
|
||||
/core/src/components/menu-toggle/ @amandaejohnston
|
||||
|
||||
/core/src/components/nav/ @sean-perkins
|
||||
/core/src/components/nav-link/ @sean-perkins
|
||||
|
||||
/core/src/components/picker/ @liamdebeasi
|
||||
/core/src/components/picker-column/ @liamdebeasi
|
||||
|
||||
/core/src/components/radio/ @amandaejohnston
|
||||
/core/src/components/radio-group/ @amandaejohnston
|
||||
|
||||
/core/src/components/refresher/ @liamdebeasi
|
||||
/core/src/components/refresher-content/ @liamdebeasi
|
||||
|
||||
/core/src/components/searchbar/ @brandyscarney
|
||||
|
||||
/core/src/components/segment/ @brandyscarney
|
||||
/core/src/components/segment-button/ @brandyscarney
|
||||
|
||||
/core/src/components/skeleton-text/ @brandyscarney
|
||||
|
||||
# Utilities
|
||||
|
||||
/core/src/utils/animation/ @liamdebeasi
|
||||
/core/src/utils/content/ @sean-perkins
|
||||
/core/src/utils/gesture/ @liamdebeasi
|
||||
/core/src/utils/input-shims/ @liamdebeasi
|
||||
/core/src/utils/keyboard/ @liamdebeasi
|
||||
/core/src/utils/logging/ @amandaejohnston
|
||||
/core/src/utils/sanitization/ @liamdebeasi
|
||||
/core/src/utils/tap-click/ @liamdebeasi
|
||||
/core/src/utils/transition/ @liamdebeasi
|
||||
|
||||
/core/src/css/ @brandyscarney
|
||||
/core/src/themes/ @brandyscarney
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -25,7 +25,7 @@ Issue number: resolves #
|
||||
If this introduces a breaking change:
|
||||
1. Describe the impact and migration path for existing applications below.
|
||||
2. Update the BREAKING.md file with the breaking change.
|
||||
3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer for more information.
|
||||
3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
2
.github/workflows/assign-issues.yml
vendored
@@ -13,6 +13,6 @@ jobs:
|
||||
- name: 'Auto-assign issue'
|
||||
uses: pozil/auto-assign-issue@edee9537367a8fbc625d27f9e10aa8bad47b8723 # v1.13.0
|
||||
with:
|
||||
assignees: liamdebeasi, sean-perkins, brandyscarney, amandaejohnston, mapsandapps, thetaPC
|
||||
assignees: liamdebeasi, sean-perkins, brandyscarney, amandaejohnston, thetaPC
|
||||
numOfAssignee: 1
|
||||
allowSelfAssign: false
|
||||
|
||||
8
.github/workflows/release-ionic.yml
vendored
@@ -41,8 +41,8 @@ jobs:
|
||||
uses: ./.github/workflows/actions/upload-archive
|
||||
with:
|
||||
name: ionic-docs
|
||||
output: docs/DocsBuild.zip
|
||||
paths: docs/core.json docs/core.d.ts
|
||||
output: packages/docs/DocsBuild.zip
|
||||
paths: packages/docs/core.json packages/docs/core.d.ts
|
||||
|
||||
release-docs:
|
||||
needs: [release-core]
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: ./.github/workflows/actions/download-archive
|
||||
with:
|
||||
name: ionic-docs
|
||||
path: ./docs
|
||||
path: ./packages/docs
|
||||
filename: DocsBuild.zip
|
||||
- uses: ./.github/workflows/actions/publish-npm
|
||||
with:
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
tag: ${{ inputs.tag }}
|
||||
version: ${{ inputs.version }}
|
||||
preid: ${{ inputs.preid }}
|
||||
working-directory: 'docs'
|
||||
working-directory: 'packages/docs'
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
release-angular:
|
||||
|
||||
61
CHANGELOG.md
@@ -3,6 +3,67 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
## [7.8.3](https://github.com/ionic-team/ionic-framework/compare/v7.8.2...v7.8.3) (2024-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** activated outline button in toolbar no longer blends into background on MD dark mode ([#29216](https://github.com/ionic-team/ionic-framework/issues/29216)) ([ee5da7a](https://github.com/ionic-team/ionic-framework/commit/ee5da7a747c0a0b420c5e371a9fe9ec4938d179e))
|
||||
* **popover:** viewport can be scrolled if no content present ([#29215](https://github.com/ionic-team/ionic-framework/issues/29215)) ([f08759c](https://github.com/ionic-team/ionic-framework/commit/f08759c2b8256ff66f8d1901bd8e0be4617db262)), closes [#29211](https://github.com/ionic-team/ionic-framework/issues/29211)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-rc.0](https://github.com/ionic-team/ionic-framework/compare/v8.0.0-beta.4...v8.0.0-rc.0) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package ionic-framework
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-beta.4](https://github.com/ionic-team/ionic-framework/compare/v8.0.0-beta.3...v8.0.0-beta.4) (2024-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** schematics account for new theme files ([#29185](https://github.com/ionic-team/ionic-framework/issues/29185)) ([b0a10df](https://github.com/ionic-team/ionic-framework/commit/b0a10dfa56a65ee3905cc2c3d48d2221a42f222f))
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **haptics:** remove cordova haptics support ([#29186](https://github.com/ionic-team/ionic-framework/issues/29186)) ([9efeb0a](https://github.com/ionic-team/ionic-framework/commit/9efeb0ad31aadee5f5ae542641d928ecf93fe82a))
|
||||
* **searchbar:** autocapitalize defaults to off ([#29107](https://github.com/ionic-team/ionic-framework/issues/29107)) ([6e477b7](https://github.com/ionic-team/ionic-framework/commit/6e477b743e41b2b37627c8208901704f599b762a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **button:** add circular shape as round ([#29161](https://github.com/ionic-team/ionic-framework/issues/29161)) ([44529f0](https://github.com/ionic-team/ionic-framework/commit/44529f0a62f1b1ce42750a20f19e829b2789febd))
|
||||
* **input:** add input-password-toggle component ([#29175](https://github.com/ionic-team/ionic-framework/issues/29175)) ([6c500fd](https://github.com/ionic-team/ionic-framework/commit/6c500fd6b2e2553c11fcddc9d86ac9a29f76e172))
|
||||
* remove css animations support for ionic animations ([#29123](https://github.com/ionic-team/ionic-framework/issues/29123)) ([892594d](https://github.com/ionic-team/ionic-framework/commit/892594de0665e8fc5c8a737d292812842ea03d64))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **searchbar:** The `autocapitalize` property on Searchbar now defaults to `'off'`.
|
||||
* **haptics:** Support for the Cordova Haptics plugin has been removed. Components that integrate with haptics, such as `ion-picker` and `ion-toggle`, will continue to function but will no longer play haptics in Cordova environments. Developers should migrate to Capacitor to continue to have haptics in these components.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.2](https://github.com/ionic-team/ionic-framework/compare/v7.8.1...v7.8.2) (2024-03-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **searchbar:** autocapitalize is initialized correctly ([#29197](https://github.com/ionic-team/ionic-framework/issues/29197)) ([8ad66c0](https://github.com/ionic-team/ionic-framework/commit/8ad66c03d777edcab19c97cba696b171acc2d2e8)), closes [#29193](https://github.com/ionic-team/ionic-framework/issues/29193)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-beta.3](https://github.com/ionic-team/ionic-framework/compare/v8.0.0-beta.2...v8.0.0-beta.3) (2024-03-20)
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a href="https://github.com/ionic-team/ionic-framework/blob/main/LICENSE">
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Ionic Framework is released under the MIT license." />
|
||||
</a>
|
||||
<a href="https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md">
|
||||
<a href="https://github.com/ionic-team/ionic/blob/main/docs/CONTRIBUTING.md">
|
||||
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome!" />
|
||||
</a>
|
||||
<a href="https://twitter.com/Ionicframework">
|
||||
@@ -38,7 +38,7 @@
|
||||
Documentation
|
||||
</a>
|
||||
<span> · </span>
|
||||
<a href="https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md">Contribute</a>
|
||||
<a href="https://github.com/ionic-team/ionic/blob/main/docs/CONTRIBUTING.md">Contribute</a>
|
||||
<span> · </span>
|
||||
<a href="https://blog.ionicframework.com/">Blog</a>
|
||||
<br />
|
||||
@@ -88,7 +88,7 @@ The Ionic Conference App is a full featured Ionic app. It is the perfect startin
|
||||
### Contributing
|
||||
|
||||
Thanks for your interest in contributing! Read up on our guidelines for
|
||||
[contributing](https://github.com/ionic-team/ionic/blob/main/.github/CONTRIBUTING.md)
|
||||
[contributing](https://github.com/ionic-team/ionic/blob/main/docs/CONTRIBUTING.md)
|
||||
and then look through our issues with a [help wanted](https://github.com/ionic-team/ionic/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
|
||||
label.
|
||||
|
||||
|
||||
@@ -3,6 +3,63 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
## [7.8.3](https://github.com/ionic-team/ionic-framework/compare/v7.8.2...v7.8.3) (2024-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **button:** activated outline button in toolbar no longer blends into background on MD dark mode ([#29216](https://github.com/ionic-team/ionic-framework/issues/29216)) ([ee5da7a](https://github.com/ionic-team/ionic-framework/commit/ee5da7a747c0a0b420c5e371a9fe9ec4938d179e))
|
||||
* **popover:** viewport can be scrolled if no content present ([#29215](https://github.com/ionic-team/ionic-framework/issues/29215)) ([f08759c](https://github.com/ionic-team/ionic-framework/commit/f08759c2b8256ff66f8d1901bd8e0be4617db262)), closes [#29211](https://github.com/ionic-team/ionic-framework/issues/29211)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-rc.0](https://github.com/ionic-team/ionic-framework/compare/v8.0.0-beta.4...v8.0.0-rc.0) (2024-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ionic/core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-beta.4](https://github.com/ionic-team/ionic-framework/compare/v8.0.0-beta.3...v8.0.0-beta.4) (2024-03-27)
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **haptics:** remove cordova haptics support ([#29186](https://github.com/ionic-team/ionic-framework/issues/29186)) ([9efeb0a](https://github.com/ionic-team/ionic-framework/commit/9efeb0ad31aadee5f5ae542641d928ecf93fe82a))
|
||||
* **searchbar:** autocapitalize defaults to off ([#29107](https://github.com/ionic-team/ionic-framework/issues/29107)) ([6e477b7](https://github.com/ionic-team/ionic-framework/commit/6e477b743e41b2b37627c8208901704f599b762a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **button:** add circular shape as round ([#29161](https://github.com/ionic-team/ionic-framework/issues/29161)) ([44529f0](https://github.com/ionic-team/ionic-framework/commit/44529f0a62f1b1ce42750a20f19e829b2789febd))
|
||||
* **input:** add input-password-toggle component ([#29175](https://github.com/ionic-team/ionic-framework/issues/29175)) ([6c500fd](https://github.com/ionic-team/ionic-framework/commit/6c500fd6b2e2553c11fcddc9d86ac9a29f76e172))
|
||||
* remove css animations support for ionic animations ([#29123](https://github.com/ionic-team/ionic-framework/issues/29123)) ([892594d](https://github.com/ionic-team/ionic-framework/commit/892594de0665e8fc5c8a737d292812842ea03d64))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* **searchbar:** The `autocapitalize` property on Searchbar now defaults to `'off'`.
|
||||
* **haptics:** Support for the Cordova Haptics plugin has been removed. Components that integrate with haptics, such as `ion-picker` and `ion-toggle`, will continue to function but will no longer play haptics in Cordova environments. Developers should migrate to Capacitor to continue to have haptics in these components.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.2](https://github.com/ionic-team/ionic-framework/compare/v7.8.1...v7.8.2) (2024-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **searchbar:** autocapitalize is initialized correctly ([#29197](https://github.com/ionic-team/ionic-framework/issues/29197)) ([8ad66c0](https://github.com/ionic-team/ionic-framework/commit/8ad66c03d777edcab19c97cba696b171acc2d2e8)), closes [#29193](https://github.com/ionic-team/ionic-framework/issues/29193)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [8.0.0-beta.3](https://github.com/ionic-team/ionic-framework/compare/v7.8.1...v8.0.0-beta.3) (2024-03-20)
|
||||
|
||||
|
||||
|
||||
@@ -361,6 +361,7 @@ ion-col,css-prop,--ion-grid-columns
|
||||
|
||||
ion-content,shadow
|
||||
ion-content,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||
ion-content,prop,fixedSlotPlacement,"after" | "before",'after',false,false
|
||||
ion-content,prop,forceOverscroll,boolean | undefined,undefined,false,false
|
||||
ion-content,prop,fullscreen,boolean,false,false,false
|
||||
ion-content,prop,scrollEvents,boolean,false,false,false
|
||||
@@ -553,6 +554,7 @@ ion-input,prop,autocomplete,"name" | "email" | "tel" | "url" | "on" | "off" | "h
|
||||
ion-input,prop,autocorrect,"off" | "on",'off',false,false
|
||||
ion-input,prop,autofocus,boolean,false,false,false
|
||||
ion-input,prop,clearInput,boolean,false,false,false
|
||||
ion-input,prop,clearInputIcon,string | undefined,undefined,false,false
|
||||
ion-input,prop,clearOnEdit,boolean | undefined,undefined,false,false
|
||||
ion-input,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||
ion-input,prop,counter,boolean,false,false,false
|
||||
@@ -829,6 +831,7 @@ ion-modal,prop,backdropDismiss,boolean,true,false,false
|
||||
ion-modal,prop,breakpoints,number[] | undefined,undefined,false,false
|
||||
ion-modal,prop,canDismiss,((data?: any, role?: string | undefined) => Promise<boolean>) | boolean,true,false,false
|
||||
ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-modal,prop,focusTrap,boolean,true,false,false
|
||||
ion-modal,prop,handle,boolean | undefined,undefined,false,false
|
||||
ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'none',false,false
|
||||
ion-modal,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
|
||||
@@ -977,6 +980,7 @@ ion-popover,prop,componentProps,undefined | { [key: string]: any; },undefined,fa
|
||||
ion-popover,prop,dismissOnSelect,boolean,false,false,false
|
||||
ion-popover,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-popover,prop,event,any,undefined,false,false
|
||||
ion-popover,prop,focusTrap,boolean,true,false,false
|
||||
ion-popover,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
|
||||
ion-popover,prop,isOpen,boolean,false,false,false
|
||||
ion-popover,prop,keepContentsMounted,boolean,false,false,false
|
||||
|
||||
40
core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.0.0-beta.3",
|
||||
"version": "8.0.0-rc.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "8.0.0-beta.3",
|
||||
"version": "8.0.0-rc.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.12.2",
|
||||
@@ -633,9 +633,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@capacitor/core": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.3.tgz",
|
||||
"integrity": "sha512-xEuQmP+h0tugl2N+qRcdrUavZydvTnnmtvqu/OtCBb/bKZo2PDRFft7MxuQRE2GxXs6kLy3cvwzhDAHB3a+9mw==",
|
||||
"version": "5.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.4.tgz",
|
||||
"integrity": "sha512-iZBgvx3o4amzKv5ttA+QHB6i7cxK+/mYpCQd1tnSdipg6ZkvfBhg1HkzhEqHk+I7MNur+QwgYDZho9+ycHRwOw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
@@ -1759,9 +1759,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.12.6",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.12.6.tgz",
|
||||
"integrity": "sha512-15JO2TdaxGVKNdLZb/2TtDa+juj3XGD/V0y/disgdzYYSnajgSh06nwODfdHz9eTUh1Hisz+KIo857I1rCZrfg==",
|
||||
"version": "4.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.14.0.tgz",
|
||||
"integrity": "sha512-+s0u/KsNolXZ7tC2hEMgMA3jaNaqOhZvYKwSzjQbc0Wv+cB481Isxzo7ifgEWRYqsJzNSyqhO6cyu/EJrGGTdg==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -1793,9 +1793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/vue-output-target": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.8.7.tgz",
|
||||
"integrity": "sha512-hgOzbKKgLdCFrhLpmaw/qQrPSXl6hZ09K+j3p/iWh3esq6sxnwuW1PJKLniwkT4Z/JlDIk6stGPGQYi+WE5I2Q==",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.8.8.tgz",
|
||||
"integrity": "sha512-xrpz92lmTuLgwY9CLgl2Q14+zBXfBuXiRS6uXFPfeaFo0pe+do8cZitOOQ8i8tcoCa/tAqgD9B9CD+yQehSIGg==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@stencil/core": ">=2.0.0 || >=3 || >= 4.0.0-beta.0 || >= 4.0.0"
|
||||
@@ -10416,9 +10416,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@capacitor/core": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.3.tgz",
|
||||
"integrity": "sha512-xEuQmP+h0tugl2N+qRcdrUavZydvTnnmtvqu/OtCBb/bKZo2PDRFft7MxuQRE2GxXs6kLy3cvwzhDAHB3a+9mw==",
|
||||
"version": "5.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.7.4.tgz",
|
||||
"integrity": "sha512-iZBgvx3o4amzKv5ttA+QHB6i7cxK+/mYpCQd1tnSdipg6ZkvfBhg1HkzhEqHk+I7MNur+QwgYDZho9+ycHRwOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
@@ -11229,9 +11229,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.12.6",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.12.6.tgz",
|
||||
"integrity": "sha512-15JO2TdaxGVKNdLZb/2TtDa+juj3XGD/V0y/disgdzYYSnajgSh06nwODfdHz9eTUh1Hisz+KIo857I1rCZrfg=="
|
||||
"version": "4.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.14.0.tgz",
|
||||
"integrity": "sha512-+s0u/KsNolXZ7tC2hEMgMA3jaNaqOhZvYKwSzjQbc0Wv+cB481Isxzo7ifgEWRYqsJzNSyqhO6cyu/EJrGGTdg=="
|
||||
},
|
||||
"@stencil/react-output-target": {
|
||||
"version": "0.5.3",
|
||||
@@ -11248,9 +11248,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/vue-output-target": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.8.7.tgz",
|
||||
"integrity": "sha512-hgOzbKKgLdCFrhLpmaw/qQrPSXl6hZ09K+j3p/iWh3esq6sxnwuW1PJKLniwkT4Z/JlDIk6stGPGQYi+WE5I2Q==",
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.8.8.tgz",
|
||||
"integrity": "sha512-xrpz92lmTuLgwY9CLgl2Q14+zBXfBuXiRS6uXFPfeaFo0pe+do8cZitOOQ8i8tcoCa/tAqgD9B9CD+yQehSIGg==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.0.0-beta.3",
|
||||
"version": "8.0.0-rc.0",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -77,7 +77,7 @@
|
||||
"build.docs.json": "stencil build --docs-json dist/docs.json",
|
||||
"clean": "node scripts/clean.js",
|
||||
"css.minify": "cleancss -O2 -o ./css/ionic.bundle.css ./css/ionic.bundle.css",
|
||||
"css.sass": "sass --embed-sources src/css:./css",
|
||||
"css.sass": "sass --embed-sources --style compressed src/css:./css",
|
||||
"eslint": "eslint src",
|
||||
"lint": "npm run lint.ts && npm run lint.sass && npm run prettier -- --write --cache",
|
||||
"lint.fix": "npm run lint.ts.fix && npm run lint.sass.fix && npm run prettier -- --write --cache",
|
||||
|
||||
@@ -1,44 +1,4 @@
|
||||
|
||||
## Build
|
||||
# Core Scripts
|
||||
|
||||
### 1. Clone ionic
|
||||
|
||||
git@github.com:ionic-team/ionic.git
|
||||
cd ionic
|
||||
|
||||
### 2. Run `npm install`
|
||||
|
||||
cd core
|
||||
npm install
|
||||
|
||||
|
||||
Notice that `@ionic/core` lives in `core`.
|
||||
|
||||
### 3. Run `npm start`
|
||||
|
||||
Make sure you are inside the `core` directory.
|
||||
|
||||
npm start
|
||||
|
||||
With the `dev` command, Ionic components will be built with [Stencil](https://stenciljs.com/), changes to source files are watched, a local http server will startup, and http://localhost:3333/ will open in a browser.
|
||||
|
||||
### 4. Preview
|
||||
|
||||
Navigate to http://localhost:3333/src/components/. Each component has small e2e apps found in the `test` directory, for example: http://localhost:3333/src/components/button/test/basic
|
||||
|
||||
As changes are made in an editor to source files, the e2e app will live-reload.
|
||||
|
||||
## How to contribute
|
||||
|
||||
1. `npm start` allows you to modify the components and have live reloading, just like another ionic app.
|
||||
|
||||
2. When everything looks good, run `npm run validate` to verify the tests linter and production build passes.
|
||||
|
||||
|
||||
# Deploy
|
||||
|
||||
1. `npm run prepare.deploy`
|
||||
2. Review/update changelog
|
||||
3. Commit updates using the package name and version number as the commit message.
|
||||
4. `npm run deploy`
|
||||
5. :tada:
|
||||
This file has been moved to [/docs/core/testing/preview-changes.md](/docs/core/testing/preview-changes.md).
|
||||
|
||||
32
core/src/components.d.ts
vendored
@@ -762,6 +762,10 @@ export namespace Components {
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* Controls where the fixed content is placed relative to the main content in the DOM. This can be used to control the order in which fixed elements receive keyboard focus. For example, if a FAB in the fixed slot should receive keyboard focus before the main page content, set this property to `'before'`.
|
||||
*/
|
||||
"fixedSlotPlacement": 'after' | 'before';
|
||||
/**
|
||||
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce. If the content exceeds the bounds of ionContent, nothing will change. Note, this does not disable the system bounce on iOS. That is an OS level setting.
|
||||
*/
|
||||
@@ -1162,6 +1166,10 @@ export namespace Components {
|
||||
* If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
|
||||
*/
|
||||
"clearInput": boolean;
|
||||
/**
|
||||
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
|
||||
*/
|
||||
"clearInputIcon"?: string;
|
||||
/**
|
||||
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
*/
|
||||
@@ -1715,6 +1723,10 @@ export namespace Components {
|
||||
* Animation to use when the modal is presented.
|
||||
*/
|
||||
"enterAnimation"?: AnimationBuilder;
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay. If 'false', focus will be allowed to move outside of the overlay. In most scenarios this property should remain set to `true`. Setting this property to `false` can cause severe accessibility issues as users relying on assistive technologies may be able to move focus into a confusing state. We recommend only setting this to `false` when absolutely necessary. Developers may want to consider disabling focus trapping if this overlay presents a non-Ionic overlay from a 3rd party library. Developers would disable focus trapping on the Ionic overlay when presenting the 3rd party overlay and then re-enable focus trapping when dismissing the 3rd party overlay and moving focus back to the Ionic overlay.
|
||||
*/
|
||||
"focusTrap": boolean;
|
||||
/**
|
||||
* Returns the current breakpoint of a sheet style modal
|
||||
*/
|
||||
@@ -2131,6 +2143,10 @@ export namespace Components {
|
||||
* The event to pass to the popover animation.
|
||||
*/
|
||||
"event": any;
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay. If 'false', focus will be allowed to move outside of the overlay. In most scenarios this property should remain set to `true`. Setting this property to `false` can cause severe accessibility issues as users relying on assistive technologies may be able to move focus into a confusing state. We recommend only setting this to `false` when absolutely necessary. Developers may want to consider disabling focus trapping if this overlay presents a non-Ionic overlay from a 3rd party library. Developers would disable focus trapping on the Ionic overlay when presenting the 3rd party overlay and then re-enable focus trapping when dismissing the 3rd party overlay and moving focus back to the Ionic overlay.
|
||||
*/
|
||||
"focusTrap": boolean;
|
||||
"getParentPopover": () => Promise<HTMLIonPopoverElement | null>;
|
||||
"hasController": boolean;
|
||||
/**
|
||||
@@ -5478,6 +5494,10 @@ declare namespace LocalJSX {
|
||||
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
|
||||
*/
|
||||
"color"?: Color;
|
||||
/**
|
||||
* Controls where the fixed content is placed relative to the main content in the DOM. This can be used to control the order in which fixed elements receive keyboard focus. For example, if a FAB in the fixed slot should receive keyboard focus before the main page content, set this property to `'before'`.
|
||||
*/
|
||||
"fixedSlotPlacement"?: 'after' | 'before';
|
||||
/**
|
||||
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce. If the content exceeds the bounds of ionContent, nothing will change. Note, this does not disable the system bounce on iOS. That is an OS level setting.
|
||||
*/
|
||||
@@ -5886,6 +5906,10 @@ declare namespace LocalJSX {
|
||||
* If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
|
||||
*/
|
||||
"clearInput"?: boolean;
|
||||
/**
|
||||
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
|
||||
*/
|
||||
"clearInputIcon"?: string;
|
||||
/**
|
||||
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
*/
|
||||
@@ -6441,6 +6465,10 @@ declare namespace LocalJSX {
|
||||
* Animation to use when the modal is presented.
|
||||
*/
|
||||
"enterAnimation"?: AnimationBuilder;
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay. If 'false', focus will be allowed to move outside of the overlay. In most scenarios this property should remain set to `true`. Setting this property to `false` can cause severe accessibility issues as users relying on assistive technologies may be able to move focus into a confusing state. We recommend only setting this to `false` when absolutely necessary. Developers may want to consider disabling focus trapping if this overlay presents a non-Ionic overlay from a 3rd party library. Developers would disable focus trapping on the Ionic overlay when presenting the 3rd party overlay and then re-enable focus trapping when dismissing the 3rd party overlay and moving focus back to the Ionic overlay.
|
||||
*/
|
||||
"focusTrap"?: boolean;
|
||||
/**
|
||||
* The horizontal line that displays at the top of a sheet modal. It is `true` by default when setting the `breakpoints` and `initialBreakpoint` properties.
|
||||
*/
|
||||
@@ -6787,6 +6815,10 @@ declare namespace LocalJSX {
|
||||
* The event to pass to the popover animation.
|
||||
*/
|
||||
"event"?: any;
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay. If 'false', focus will be allowed to move outside of the overlay. In most scenarios this property should remain set to `true`. Setting this property to `false` can cause severe accessibility issues as users relying on assistive technologies may be able to move focus into a confusing state. We recommend only setting this to `false` when absolutely necessary. Developers may want to consider disabling focus trapping if this overlay presents a non-Ionic overlay from a 3rd party library. Developers would disable focus trapping on the Ionic overlay when presenting the 3rd party overlay and then re-enable focus trapping when dismissing the 3rd party overlay and moving focus back to the Ionic overlay.
|
||||
*/
|
||||
"focusTrap"?: boolean;
|
||||
"hasController"?: boolean;
|
||||
/**
|
||||
* Additional attributes to pass to the popover.
|
||||
|
||||
@@ -149,7 +149,20 @@
|
||||
}
|
||||
|
||||
::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1.125em;
|
||||
/**
|
||||
* The values were provided through a native iOS app.
|
||||
* min font size: 15px, default font size: 18px, max font size: 43px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 16px
|
||||
* (derived from rem), then the base size can use the default font
|
||||
* size of the icon.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(0.84, 18px, 2.39, 1em);
|
||||
}
|
||||
|
||||
:host(.button-small.button-has-icon-only) {
|
||||
@@ -157,11 +170,23 @@
|
||||
min-width: clamp(23px, 2.16em, 54px);
|
||||
// TODO(FW-6053): replace em value with the min-height variable.
|
||||
min-height: clamp(23px, 2.16em, 54px);
|
||||
|
||||
}
|
||||
|
||||
:host(.button-small) ::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1.4em;
|
||||
/**
|
||||
* The values were provided through a native iOS app.
|
||||
* min font size: 12px, default font size: 17px, max font size: 40px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 13px
|
||||
* (derived from rem) and the default font size of the icon is
|
||||
* 17px, then the base size would need to be increased.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(0.58, 20.93px, 1.92, 1em);
|
||||
}
|
||||
|
||||
:host(.button-large.button-has-icon-only) {
|
||||
@@ -172,7 +197,20 @@
|
||||
}
|
||||
|
||||
:host(.button-large) ::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1em;
|
||||
/**
|
||||
* The values were provided through a native iOS app.
|
||||
* min font size: 15px, default font size: 18px, max font size: 43px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 20px
|
||||
* (derived from rem) and the default font size of the icon is
|
||||
* 18px, then the base size would need to be decreased.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(1.05, 14.4px, 2.99, 1em);
|
||||
}
|
||||
|
||||
// iOS Button Focused
|
||||
@@ -247,3 +285,12 @@
|
||||
:host(.button-solid.ion-color.ion-activated) .button-native::after {
|
||||
background: #{current-color(shade)};
|
||||
}
|
||||
|
||||
|
||||
// Activated Button in Toolbar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
|
||||
background: var(--ion-toolbar-color, var(--color));
|
||||
color: #{var(--ion-toolbar-background, var(--background), ion-color(primary, contrast))};
|
||||
}
|
||||
|
||||
@@ -142,7 +142,21 @@
|
||||
}
|
||||
|
||||
::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1.6em;
|
||||
/**
|
||||
* The values were provided through MD design,
|
||||
* large and small are based on the iOS sizes.
|
||||
* min font size: 15px, default font size: 22.4px, max font size: 43px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 14px
|
||||
* (derived from rem) and the default font size of the icon is
|
||||
* 22.4px, then the base size would need to be increased.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(0.59, 25.6px, 1.68, 1em);
|
||||
}
|
||||
|
||||
:host(.button-small.button-has-icon-only) {
|
||||
@@ -153,7 +167,21 @@
|
||||
}
|
||||
|
||||
:host(.button-small) ::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1.23em;
|
||||
/**
|
||||
* The values were provided through MD design,
|
||||
* large and small are based on the iOS sizes.
|
||||
* min font size: 12px, default font size: 16px, max font size: 40px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 13px
|
||||
* (derived from rem) and the default font size of the icon is
|
||||
* 16px, then the base size would need to be increased.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(0.66, 19.7px, 2.05, 1em);
|
||||
}
|
||||
|
||||
:host(.button-large.button-has-icon-only) {
|
||||
@@ -164,7 +192,21 @@
|
||||
}
|
||||
|
||||
:host(.button-large) ::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: 1.4em;
|
||||
/**
|
||||
* The values were provided through MD design,
|
||||
* large and small are based on the iOS sizes.
|
||||
* min font size: 15px, default font size: 28px, max font size: 43px
|
||||
*
|
||||
* Since the `ion-button` uses `rem` for the font size, we can't
|
||||
* just pass the desired icon font size in `em` to the `
|
||||
* dynamic-font-clamp`. Instead, we need to adjust the base size
|
||||
* to account for the ion-button` font size.
|
||||
*
|
||||
* For example, if the default font size of `ion-button` is 20px
|
||||
* (derived from rem) and the default font size of the icon is
|
||||
* 28px, then the base size would need to be increased.
|
||||
*/
|
||||
font-size: dynamic-font-clamp(0.67, 22.4px, 1.92, 1em);
|
||||
}
|
||||
|
||||
// Material Design Button: Hover
|
||||
@@ -196,3 +238,12 @@
|
||||
background: #{current-color(base)};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Activated Button in Toolbar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
|
||||
background: var(--ion-toolbar-background, var(--color));
|
||||
color: #{var(--ion-toolbar-color, var(--background), ion-color(primary, contrast))};
|
||||
}
|
||||
|
||||
@@ -325,11 +325,3 @@ ion-ripple-effect {
|
||||
background: #{var(--ion-toolbar-color, var(--background))};
|
||||
color: #{var(--ion-toolbar-background, var(--color))};
|
||||
}
|
||||
|
||||
// Activated Button in Toolbar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
|
||||
background: var(--ion-toolbar-color, var(--color));
|
||||
color: #{var(--ion-toolbar-background, var(--background), ion-color(primary, contrast))};
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -75,6 +75,15 @@ export class Content implements ComponentInterface {
|
||||
*/
|
||||
@Prop() fullscreen = false;
|
||||
|
||||
/**
|
||||
* Controls where the fixed content is placed relative to the main content
|
||||
* in the DOM. This can be used to control the order in which fixed elements
|
||||
* receive keyboard focus.
|
||||
* For example, if a FAB in the fixed slot should receive keyboard focus before
|
||||
* the main page content, set this property to `'before'`.
|
||||
*/
|
||||
@Prop() fixedSlotPlacement: 'after' | 'before' = 'after';
|
||||
|
||||
/**
|
||||
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce.
|
||||
* If the content exceeds the bounds of ionContent, nothing will change.
|
||||
@@ -423,7 +432,7 @@ export class Content implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isMainContent, scrollX, scrollY, el } = this;
|
||||
const { fixedSlotPlacement, isMainContent, scrollX, scrollY, el } = this;
|
||||
const rtl = isRTL(el) ? 'rtl' : 'ltr';
|
||||
const mode = getIonMode(this);
|
||||
const forceOverscroll = this.shouldForceOverscroll();
|
||||
@@ -446,6 +455,9 @@ export class Content implements ComponentInterface {
|
||||
}}
|
||||
>
|
||||
<div ref={(el) => (this.backgroundContentEl = el)} id="background-content" part="background"></div>
|
||||
|
||||
{fixedSlotPlacement === 'before' ? <slot name="fixed"></slot> : null}
|
||||
|
||||
<div
|
||||
class={{
|
||||
'inner-scroll': true,
|
||||
@@ -467,7 +479,7 @@ export class Content implements ComponentInterface {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<slot name="fixed"></slot>
|
||||
{fixedSlotPlacement === 'after' ? <slot name="fixed"></slot> : null}
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
|
||||
31
core/src/components/content/test/content.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
import { Content } from '../content';
|
||||
|
||||
describe('content: fixed slot placement', () => {
|
||||
it('should should fixed slot after content', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Content],
|
||||
html: '<ion-content></ion-content>',
|
||||
});
|
||||
|
||||
const content = page.body.querySelector('ion-content')!;
|
||||
const fixedSlot = content.shadowRoot!.querySelector('slot[name="fixed"]')!;
|
||||
const scrollEl = content.shadowRoot!.querySelector('[part="scroll"]')!;
|
||||
|
||||
expect(fixedSlot.nextElementSibling).not.toBe(scrollEl);
|
||||
});
|
||||
|
||||
it('should should fixed slot before content', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Content],
|
||||
html: `<ion-content fixed-slot-placement="before"></ion-content>`,
|
||||
});
|
||||
|
||||
const content = page.body.querySelector('ion-content')!;
|
||||
const fixedSlot = content.shadowRoot!.querySelector('slot[name="fixed"]')!;
|
||||
const scrollEl = content.shadowRoot!.querySelector('[part="scroll"]')!;
|
||||
|
||||
expect(fixedSlot.nextElementSibling).toBe(scrollEl);
|
||||
});
|
||||
});
|
||||
@@ -541,7 +541,7 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
if (closeOverlay) {
|
||||
this.closeParentOverlay();
|
||||
this.closeParentOverlay(CONFIRM_ROLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +566,7 @@ export class Datetime implements ComponentInterface {
|
||||
this.ionCancel.emit();
|
||||
|
||||
if (closeOverlay) {
|
||||
this.closeParentOverlay();
|
||||
this.closeParentOverlay(CANCEL_ROLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,13 +616,13 @@ export class Datetime implements ComponentInterface {
|
||||
return Array.isArray(activeParts) ? activeParts[0] : activeParts;
|
||||
};
|
||||
|
||||
private closeParentOverlay = () => {
|
||||
private closeParentOverlay = (role: string) => {
|
||||
const popoverOrModal = this.el.closest('ion-modal, ion-popover') as
|
||||
| HTMLIonModalElement
|
||||
| HTMLIonPopoverElement
|
||||
| null;
|
||||
if (popoverOrModal) {
|
||||
popoverOrModal.dismiss();
|
||||
popoverOrModal.dismiss(undefined, role);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2645,5 +2645,7 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
let datetimeIds = 0;
|
||||
const CANCEL_ROLE = 'datetime-cancel';
|
||||
const CONFIRM_ROLE = 'datetime-confirm';
|
||||
const WHEEL_ITEM_PART = 'wheel-item';
|
||||
const WHEEL_ITEM_ACTIVE_PART = `active`;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ config, title }) => {
|
||||
test.describe(title('datetime: overlay roles'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-modal>
|
||||
<ion-datetime></ion-datetime>
|
||||
</ion-modal>
|
||||
`,
|
||||
config
|
||||
);
|
||||
});
|
||||
test('should pass role to overlay when calling confirm method', async ({ page }) => {
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const modal = page.locator('ion-modal');
|
||||
const datetime = page.locator('ion-datetime');
|
||||
|
||||
await modal.evaluate((el: HTMLIonModalElement) => el.present());
|
||||
|
||||
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.confirm(true));
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
expect(ionModalDidDismiss).toHaveReceivedEventDetail({ data: undefined, role: 'datetime-confirm' });
|
||||
});
|
||||
test('should pass role to overlay when calling cancel method', async ({ page }) => {
|
||||
const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
|
||||
const modal = page.locator('ion-modal');
|
||||
const datetime = page.locator('ion-datetime');
|
||||
|
||||
await modal.evaluate((el: HTMLIonModalElement) => el.present());
|
||||
|
||||
await datetime.evaluate((el: HTMLIonDatetimeElement) => el.cancel(true));
|
||||
|
||||
await ionModalDidDismiss.next();
|
||||
expect(ionModalDidDismiss).toHaveReceivedEventDetail({ data: undefined, role: 'datetime-cancel' });
|
||||
});
|
||||
});
|
||||
});
|
||||
66
core/src/components/datetime/test/overlay-roles/index.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Datetime - Overlay Roles</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 type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
ion-modal.ios,
|
||||
ion-popover.datetime-popover.ios {
|
||||
--width: 350px;
|
||||
--height: 420px;
|
||||
}
|
||||
|
||||
ion-modal.md,
|
||||
ion-popover.datetime-popover.md {
|
||||
--width: 350px;
|
||||
--height: 450px;
|
||||
}
|
||||
|
||||
ion-datetime {
|
||||
width: 350px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Datetime - Overlay Roles</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<ion-button onclick="presentModal()">Present Modal</ion-button>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
<script>
|
||||
const presentModal = async () => {
|
||||
const modal = await createModal();
|
||||
|
||||
await modal.present();
|
||||
console.log(await modal.onDidDismiss());
|
||||
};
|
||||
|
||||
const createModal = () => {
|
||||
// create component to open
|
||||
const element = document.createElement('div');
|
||||
element.innerHTML = `
|
||||
<ion-datetime show-default-buttons="true"></ion-datetime>
|
||||
`;
|
||||
|
||||
// present the modal
|
||||
const modalElement = Object.assign(document.createElement('ion-modal'), {
|
||||
component: element,
|
||||
});
|
||||
|
||||
const app = document.querySelector('ion-app');
|
||||
app.appendChild(modalElement);
|
||||
return modalElement;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -92,6 +92,11 @@ export class Input implements ComponentInterface {
|
||||
*/
|
||||
@Prop() clearInput = false;
|
||||
|
||||
/**
|
||||
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
|
||||
*/
|
||||
@Prop() clearInputIcon?: string;
|
||||
|
||||
/**
|
||||
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
|
||||
*/
|
||||
@@ -681,11 +686,13 @@ export class Input implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus } = this;
|
||||
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus, clearInputIcon } = this;
|
||||
const mode = getIonMode(this);
|
||||
const value = this.getValue();
|
||||
const inItem = hostContext('ion-item', this.el);
|
||||
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
|
||||
const defaultClearIcon = mode === 'ios' ? closeCircle : closeSharp;
|
||||
const clearIconData = clearInputIcon ?? defaultClearIcon;
|
||||
|
||||
const hasValue = this.hasValue();
|
||||
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
|
||||
@@ -784,7 +791,7 @@ export class Input implements ComponentInterface {
|
||||
}}
|
||||
onClick={this.clearTextInput}
|
||||
>
|
||||
<ion-icon aria-hidden="true" icon={mode === 'ios' ? closeCircle : closeSharp}></ion-icon>
|
||||
<ion-icon aria-hidden="true" icon={clearIconData}></ion-icon>
|
||||
</button>
|
||||
)}
|
||||
<slot name="end"></slot>
|
||||
|
||||
@@ -99,3 +99,19 @@ describe('input: label rendering', () => {
|
||||
expect(labelText.textContent).toBe('Label Prop Text');
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/ionic-team/ionic-framework/issues/26974
|
||||
describe('input: clear icon', () => {
|
||||
it('should render custom icon', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Input],
|
||||
html: `
|
||||
<ion-input clear-input-icon="foo" clear-input="true"></ion-input>
|
||||
`,
|
||||
});
|
||||
|
||||
const icon = page.body.querySelector<HTMLIonIconElement>('ion-input ion-icon')!;
|
||||
|
||||
expect(icon.getAttribute('icon')).toBe('foo');
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@@ -1,5 +1,6 @@
|
||||
import { createGesture } from '@utils/gesture';
|
||||
import { clamp, raf } from '@utils/helpers';
|
||||
import { FOCUS_TRAP_DISABLE_CLASS } from '@utils/overlays';
|
||||
|
||||
import type { Animation } from '../../../interface';
|
||||
import type { GestureDetail } from '../../../utils/gesture';
|
||||
@@ -91,7 +92,7 @@ export const createSheetGesture = (
|
||||
* as inputs should not be focusable outside
|
||||
* the sheet.
|
||||
*/
|
||||
baseEl.classList.remove('ion-disable-focus-trap');
|
||||
baseEl.classList.remove(FOCUS_TRAP_DISABLE_CLASS);
|
||||
};
|
||||
|
||||
const disableBackdrop = () => {
|
||||
@@ -105,7 +106,7 @@ export const createSheetGesture = (
|
||||
* Adding this class disables focus trapping
|
||||
* for the sheet temporarily.
|
||||
*/
|
||||
baseEl.classList.add('ion-disable-focus-trap');
|
||||
baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
present,
|
||||
createTriggerController,
|
||||
setOverlayId,
|
||||
FOCUS_TRAP_DISABLE_CLASS,
|
||||
} from '@utils/overlays';
|
||||
import { getClassMap } from '@utils/theme';
|
||||
import { deepReady, waitForMount } from '@utils/transition';
|
||||
@@ -257,6 +258,25 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
*/
|
||||
@Prop() keepContentsMounted = false;
|
||||
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay.
|
||||
* If 'false', focus will be allowed to move outside of the overlay.
|
||||
*
|
||||
* In most scenarios this property should remain set to `true`. Setting
|
||||
* this property to `false` can cause severe accessibility issues as users
|
||||
* relying on assistive technologies may be able to move focus into
|
||||
* a confusing state. We recommend only setting this to `false` when
|
||||
* absolutely necessary.
|
||||
*
|
||||
* Developers may want to consider disabling focus trapping if this
|
||||
* overlay presents a non-Ionic overlay from a 3rd party library.
|
||||
* Developers would disable focus trapping on the Ionic overlay
|
||||
* when presenting the 3rd party overlay and then re-enable
|
||||
* focus trapping when dismissing the 3rd party overlay and moving
|
||||
* focus back to the Ionic overlay.
|
||||
*/
|
||||
@Prop() focusTrap = true;
|
||||
|
||||
/**
|
||||
* Determines whether or not a modal can dismiss
|
||||
* when calling the `dismiss` method.
|
||||
@@ -905,7 +925,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes } = this;
|
||||
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap } =
|
||||
this;
|
||||
|
||||
const showHandle = handle !== false && isSheetModal;
|
||||
const mode = getIonMode(this);
|
||||
@@ -926,6 +947,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
[`modal-card`]: isCardModal,
|
||||
[`modal-sheet`]: isSheetModal,
|
||||
'overlay-hidden': true,
|
||||
[FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false,
|
||||
...getClassMap(this.cssClass),
|
||||
}}
|
||||
onIonBackdropTap={this.onBackdropTap}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { h } from '@stencil/core';
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
import { Modal } from '../../modal';
|
||||
import { FOCUS_TRAP_DISABLE_CLASS } from '@utils/overlays';
|
||||
|
||||
describe('modal: htmlAttributes inheritance', () => {
|
||||
it('should correctly inherit attributes on host', async () => {
|
||||
@@ -15,3 +16,26 @@ describe('modal: htmlAttributes inheritance', () => {
|
||||
await expect(modal.getAttribute('data-testid')).toBe('basic-modal');
|
||||
});
|
||||
});
|
||||
|
||||
describe('modal: focus trap', () => {
|
||||
it('should set the focus trap class when disabled', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Modal],
|
||||
template: () => <ion-modal focusTrap={false} overlayIndex={1}></ion-modal>,
|
||||
});
|
||||
|
||||
const modal = page.body.querySelector('ion-modal')!;
|
||||
|
||||
expect(modal.classList.contains(FOCUS_TRAP_DISABLE_CLASS)).toBe(true);
|
||||
});
|
||||
it('should not set the focus trap class by default', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Modal],
|
||||
template: () => <ion-modal overlayIndex={1}></ion-modal>,
|
||||
});
|
||||
|
||||
const modal = page.body.querySelector('ion-modal')!;
|
||||
|
||||
expect(modal.classList.contains(FOCUS_TRAP_DISABLE_CLASS)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Nested Popovers
|
||||
|
||||
@@ -5,7 +5,15 @@ import { CoreDelegate, attachComponent, detachComponent } from '@utils/framework
|
||||
import { addEventListener, raf, hasLazyBuild } from '@utils/helpers';
|
||||
import { createLockController } from '@utils/lock-controller';
|
||||
import { printIonWarning } from '@utils/logging';
|
||||
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present, setOverlayId } from '@utils/overlays';
|
||||
import {
|
||||
BACKDROP,
|
||||
dismiss,
|
||||
eventMethod,
|
||||
prepareOverlay,
|
||||
present,
|
||||
setOverlayId,
|
||||
FOCUS_TRAP_DISABLE_CLASS,
|
||||
} from '@utils/overlays';
|
||||
import { isPlatform } from '@utils/platform';
|
||||
import { getClassMap } from '@utils/theme';
|
||||
import { deepReady, waitForMount } from '@utils/transition';
|
||||
@@ -236,6 +244,25 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
*/
|
||||
@Prop() keyboardEvents = false;
|
||||
|
||||
/**
|
||||
* If `true`, focus will not be allowed to move outside of this overlay.
|
||||
* If 'false', focus will be allowed to move outside of the overlay.
|
||||
*
|
||||
* In most scenarios this property should remain set to `true`. Setting
|
||||
* this property to `false` can cause severe accessibility issues as users
|
||||
* relying on assistive technologies may be able to move focus into
|
||||
* a confusing state. We recommend only setting this to `false` when
|
||||
* absolutely necessary.
|
||||
*
|
||||
* Developers may want to consider disabling focus trapping if this
|
||||
* overlay presents a non-Ionic overlay from a 3rd party library.
|
||||
* Developers would disable focus trapping on the Ionic overlay
|
||||
* when presenting the 3rd party overlay and then re-enable
|
||||
* focus trapping when dismissing the 3rd party overlay and moving
|
||||
* focus back to the Ionic overlay.
|
||||
*/
|
||||
@Prop() focusTrap = true;
|
||||
|
||||
@Watch('trigger')
|
||||
@Watch('triggerAction')
|
||||
onTriggerChange() {
|
||||
@@ -656,7 +683,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
|
||||
render() {
|
||||
const mode = getIonMode(this);
|
||||
const { onLifecycle, parentPopover, dismissOnSelect, side, arrow, htmlAttributes } = this;
|
||||
const { onLifecycle, parentPopover, dismissOnSelect, side, arrow, htmlAttributes, focusTrap } = this;
|
||||
const desktop = isPlatform('desktop');
|
||||
const enableArrow = arrow && !parentPopover;
|
||||
|
||||
@@ -676,6 +703,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
'overlay-hidden': true,
|
||||
'popover-desktop': desktop,
|
||||
[`popover-side-${side}`]: true,
|
||||
[FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false,
|
||||
'popover-nested': !!parentPopover,
|
||||
}}
|
||||
onIonPopoverDidPresent={onLifecycle}
|
||||
|
||||
@@ -48,6 +48,98 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
* Translucent popovers are only available on iOS
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('popover: scrolling'), async () => {
|
||||
test.beforeEach(({ skip }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/29211',
|
||||
});
|
||||
// We are testing if Ionic sets overflow is set correctly on elements,
|
||||
// so we do not need to test across browsers
|
||||
skip.browser('webkit', 'Behavior does not vary across browsers');
|
||||
skip.browser('firefox', 'Behavior does not vary across browsers');
|
||||
});
|
||||
test('should scroll to bottom without IonContent', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
ion-popover {
|
||||
--height: 150px;
|
||||
}
|
||||
</style>
|
||||
<ion-popover>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
</ion-popover>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const popover = page.locator('ion-popover');
|
||||
const viewport = popover.locator('.popover-viewport');
|
||||
const p = popover.locator('p');
|
||||
const lastP = await p.last();
|
||||
|
||||
await popover.evaluate((el: HTMLIonPopoverElement) => el.present());
|
||||
|
||||
await expect(lastP).not.toBeInViewport();
|
||||
|
||||
// hover over viewport and scroll to bottom
|
||||
await viewport.hover();
|
||||
await page.mouse.wheel(0, 500);
|
||||
|
||||
await expect(lastP).toBeInViewport();
|
||||
});
|
||||
test('should scroll to bottom with IonContent', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
ion-popover {
|
||||
--height: 150px;
|
||||
}
|
||||
</style>
|
||||
<ion-popover>
|
||||
<ion-content>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
<p>Text</p>
|
||||
</ion-content>
|
||||
</ion-popover>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const popover = page.locator('ion-popover');
|
||||
const content = popover.locator('ion-content');
|
||||
const p = popover.locator('p');
|
||||
const lastP = await p.last();
|
||||
|
||||
await popover.evaluate((el: HTMLIonPopoverElement) => el.present());
|
||||
|
||||
await expect(lastP).not.toBeInViewport();
|
||||
|
||||
// hover over viewport and scroll to bottom
|
||||
await content.hover();
|
||||
await page.mouse.wheel(0, 500);
|
||||
|
||||
await expect(lastP).toBeInViewport();
|
||||
});
|
||||
});
|
||||
test.describe(title('popover: translucent variants'), async () => {
|
||||
let popoverFixture!: PopoverFixture;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
import { Popover } from '../../popover';
|
||||
|
||||
import { FOCUS_TRAP_DISABLE_CLASS } from '@utils/overlays';
|
||||
|
||||
describe('popover: htmlAttributes inheritance', () => {
|
||||
it('should correctly inherit attributes on host', async () => {
|
||||
const page = await newSpecPage({
|
||||
@@ -15,3 +17,26 @@ describe('popover: htmlAttributes inheritance', () => {
|
||||
await expect(popover.getAttribute('data-testid')).toBe('basic-popover');
|
||||
});
|
||||
});
|
||||
|
||||
describe('popover: focus trap', () => {
|
||||
it('should set the focus trap class when disabled', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Popover],
|
||||
template: () => <ion-popover focusTrap={false} overlayIndex={1}></ion-popover>,
|
||||
});
|
||||
|
||||
const popover = page.body.querySelector('ion-popover')!;
|
||||
|
||||
expect(popover.classList.contains(FOCUS_TRAP_DISABLE_CLASS)).toBe(true);
|
||||
});
|
||||
it('should not set the focus trap class by default', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Popover],
|
||||
template: () => <ion-popover overlayIndex={1}></ion-popover>,
|
||||
});
|
||||
|
||||
const popover = page.body.querySelector('ion-popover')!;
|
||||
|
||||
expect(popover.classList.contains(FOCUS_TRAP_DISABLE_CLASS)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -606,7 +606,7 @@ export class Searchbar implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { cancelButtonText } = this;
|
||||
const { cancelButtonText, autocapitalize } = this;
|
||||
const animated = this.animated && config.getBoolean('animated', true);
|
||||
const mode = getIonMode(this);
|
||||
const clearIcon = this.clearIcon || (mode === 'ios' ? closeCircle : closeSharp);
|
||||
@@ -668,7 +668,7 @@ export class Searchbar implements ComponentInterface {
|
||||
placeholder={this.placeholder}
|
||||
type={this.type}
|
||||
value={this.getValue()}
|
||||
autoCapitalize={this.autocapitalize}
|
||||
autoCapitalize={autocapitalize === 'default' ? undefined : autocapitalize}
|
||||
autoComplete={this.autocomplete}
|
||||
autoCorrect={this.autocorrect}
|
||||
spellcheck={this.spellcheck}
|
||||
|
||||
@@ -1,14 +1,160 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs().forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('toolbar: basic'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.goto(`/src/components/toolbar/test/basic`, config);
|
||||
configs({ palettes: ['light', 'dark'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('toolbar: basic (LTR only)'), () => {
|
||||
test('should not have visual regressions with text only', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Toolbar</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
// capture both header toolbars at once, but don't include all the white space in the ion-content
|
||||
const header = page.locator('ion-header');
|
||||
await expect(header).toHaveScreenshot(screenshot(`toolbar-basic`));
|
||||
await expect(header).toHaveScreenshot(screenshot(`toolbar-basic-text-only`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
configs({ palettes: ['light', 'dark'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('toolbar: basic'), () => {
|
||||
test('should truncate long title with ellipsis', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>This is the title that never ends. It just goes on and on my friend.</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const header = page.locator('ion-header');
|
||||
await expect(header).toHaveScreenshot(screenshot(`toolbar-basic-long-text`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions with icon-only buttons', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button>
|
||||
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-button>
|
||||
<ion-icon slot="icon-only" name="search"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button color="secondary">
|
||||
<ion-icon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Toolbar</ion-title>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button class="ion-activated">
|
||||
<ion-icon slot="icon-only" name="person-circle"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-button class="ion-activated">
|
||||
<ion-icon slot="icon-only" name="search"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button color="secondary" class="ion-activated">
|
||||
<ion-icon slot="icon-only" ios="ellipsis-horizontal" md="ellipsis-vertical"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Activated Buttons</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const header = page.locator('ion-header');
|
||||
await expect(header).toHaveScreenshot(screenshot(`toolbar-basic-icon-buttons`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions with buttons with icons and text', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button fill="solid">
|
||||
<ion-icon slot="start" name="person-circle"></ion-icon>
|
||||
Solid
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Solid</ion-title>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button fill="solid" color="secondary">
|
||||
Help
|
||||
<ion-icon slot="end" name="help-circle"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button fill="solid" class="ion-activated">
|
||||
<ion-icon slot="start" name="person-circle"></ion-icon>
|
||||
Solid
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Solid Activated</ion-title>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button fill="solid" color="secondary" class="ion-activated">
|
||||
Help
|
||||
<ion-icon slot="end" name="help-circle"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button fill="outline">
|
||||
<ion-icon slot="start" name="star"></ion-icon>
|
||||
Star
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Outline</ion-title>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button color="secondary" fill="outline">
|
||||
Info
|
||||
<ion-icon slot="end" name="information-circle"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="secondary">
|
||||
<ion-button fill="outline" class="ion-activated">
|
||||
<ion-icon slot="start" name="star"></ion-icon>
|
||||
Star
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Outline Activated</ion-title>
|
||||
<ion-buttons slot="primary">
|
||||
<ion-button color="secondary" fill="outline" class="ion-activated">
|
||||
Info
|
||||
<ion-icon slot="end" name="information-circle"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const header = page.locator('ion-header');
|
||||
await expect(header).toHaveScreenshot(screenshot(`toolbar-basic-text-icon-buttons`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 7.6 KiB |