Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b231503c6 | ||
|
|
ecfb0e1977 | ||
|
|
0fecc4f154 | ||
|
|
4798c69d59 | ||
|
|
5ce0c609f3 | ||
|
|
f69aa8cd21 | ||
|
|
c69adbf988 | ||
|
|
3f3f196a24 | ||
|
|
ffce443585 | ||
|
|
bfaf528e61 | ||
|
|
4efdc88a29 | ||
|
|
7b90025d31 | ||
|
|
176bb43262 | ||
|
|
c9916ff4b5 | ||
|
|
9738228bc0 | ||
|
|
a448a88500 | ||
|
|
1388014b65 | ||
|
|
1073d22b56 | ||
|
|
cea0b493fc | ||
|
|
3d9871a77f | ||
|
|
b315b0cb29 | ||
|
|
7b6c330f17 | ||
|
|
b3cd49bf22 | ||
|
|
6c36cef241 | ||
|
|
cca824d195 | ||
|
|
b5cb828861 | ||
|
|
101ad5402f | ||
|
|
de35fa8b94 | ||
|
|
c766528a17 | ||
|
|
9b3cf9fbc2 | ||
|
|
ee5da7a747 | ||
|
|
c4bfc783e0 | ||
|
|
0137e732ce | ||
|
|
88ecb29e39 | ||
|
|
f726c35868 | ||
|
|
4a9d84ecbd | ||
|
|
f08759c2b8 | ||
|
|
2053bc77a6 | ||
|
|
c23be1befd | ||
|
|
a2923aaeb3 | ||
|
|
eeab96de55 | ||
|
|
ca0923812a | ||
|
|
1be956bd18 | ||
|
|
8ad66c03d7 | ||
|
|
d1253c08c1 | ||
|
|
7ca6b80b04 | ||
|
|
4cd8fb15af | ||
|
|
58d217d0cf | ||
|
|
73d661a3a2 | ||
|
|
fc5d692a05 | ||
|
|
e50d32a388 | ||
|
|
55464ddf84 | ||
|
|
e98620ee99 | ||
|
|
02f89bbc42 | ||
|
|
f75977699d | ||
|
|
fdfecd32c3 | ||
|
|
d67fdcc43a | ||
|
|
9ed692ce4f | ||
|
|
5a42841d52 | ||
|
|
19c1bc16cb | ||
|
|
459a023bac | ||
|
|
0a66ebe321 | ||
|
|
7be6d9f72d | ||
|
|
2417750cbf | ||
|
|
977e79db71 | ||
|
|
9709c68372 | ||
|
|
75608d57d4 | ||
|
|
ce07e6af81 | ||
|
|
18aa3cdf2b | ||
|
|
a390682d75 |
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-internal/ @liamdebeasi
|
||||
/core/src/components/picker-column-internal/ @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.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
@@ -21,33 +21,13 @@ runs:
|
||||
name: ionic-core
|
||||
path: ./core
|
||||
filename: CoreBuild.zip
|
||||
- name: Install Playwright Dependencies
|
||||
run: npm install && npx playwright install && npx playwright install-deps
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
shell: bash
|
||||
working-directory: ./core
|
||||
- id: clean-component-name
|
||||
name: Clean Component Name
|
||||
# Remove `ion-` prefix from the `component` variable if it exists.
|
||||
run: |
|
||||
echo "component=$(echo ${{ inputs.component }} | sed 's/ion-//g')" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
- id: set-test-file
|
||||
name: Set Test File
|
||||
# Screenshots can be updated for all components or specified component(s).
|
||||
# If the `component` variable is set, then the test has the option to
|
||||
# - run all the file paths that are in a component folder.
|
||||
# -- For example: if the `component` value is "item", then the test will run all the file paths that are in the "src/components/item" folder.
|
||||
# -- For example: if the `component` value is "item chip", then the test will run all the file paths that are in the "src/components/item" and "src/components/chip" folders.
|
||||
run: |
|
||||
if [ -n "${{ steps.clean-component-name.outputs.component }}" ]; then
|
||||
echo "testFile=\$(echo '${{ steps.clean-component-name.outputs.component }}' | awk '{for(i=1;i<=NF;i++) \$i=\"src/components/\"\$i}1')" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "testFile=$(echo '')" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
shell: bash
|
||||
- name: Test
|
||||
if: inputs.update != 'true'
|
||||
run: npm run test.e2e ${{ steps.set-test-file.outputs.testFile }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
|
||||
run: npm run test.e2e.docker.ci ${{ inputs.component }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
|
||||
shell: bash
|
||||
working-directory: ./core
|
||||
- name: Test and Update
|
||||
@@ -69,7 +49,7 @@ runs:
|
||||
# which is why we not using the upload-archive
|
||||
# composite step here.
|
||||
run: |
|
||||
npm run test.e2e ${{ steps.set-test-file.outputs.testFile }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
|
||||
npm run test.e2e.docker.ci ${{ inputs.component }} -- --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
|
||||
git add src/\*.png --force
|
||||
mkdir updated-screenshots
|
||||
cd ../ && rsync -R --progress $(git diff --name-only --cached) core/updated-screenshots
|
||||
|
||||
@@ -25,12 +25,9 @@ runs:
|
||||
# Configure user as Ionitron
|
||||
# and push only the changed .png snapshots
|
||||
# to the remote branch.
|
||||
# Screenshots are in .gitignore
|
||||
# Non-Linux screenshots are in .gitignore
|
||||
# to prevent local screenshots from getting
|
||||
# pushed to Git. As a result, we need --force
|
||||
# here so that CI generated screenshots can
|
||||
# get added to git. Screenshot ground truths
|
||||
# should only be added via this CI process.
|
||||
# pushed to Git.
|
||||
run: |
|
||||
git config user.name ionitron
|
||||
git config user.email hi@ionicframework.com
|
||||
@@ -38,7 +35,7 @@ runs:
|
||||
# This adds an empty entry for new
|
||||
# screenshot files so we can track them with
|
||||
# git diff
|
||||
git add src/\*.png --force -N
|
||||
git add src/\*.png -N
|
||||
|
||||
if git diff --exit-code; then
|
||||
echo -e "\033[1;31m⚠️ Error: No new screenshots generated ⚠️\033[0m"
|
||||
@@ -48,7 +45,7 @@ runs:
|
||||
else
|
||||
# This actually adds the contents
|
||||
# of the screenshots (including new ones)
|
||||
git add src/\*.png --force
|
||||
git add src/\*.png
|
||||
git commit -m "chore(): add updated snapshots"
|
||||
git push
|
||||
fi
|
||||
|
||||
4
.github/workflows/assign-issues.yml
vendored
@@ -11,8 +11,8 @@ jobs:
|
||||
issues: write
|
||||
steps:
|
||||
- name: 'Auto-assign issue'
|
||||
uses: pozil/auto-assign-issue@edee9537367a8fbc625d27f9e10aa8bad47b8723 # v1.13.0
|
||||
uses: pozil/auto-assign-issue@65947009a243e6b3993edeef4e64df3ca85d760c # v1.14.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:
|
||||
|
||||
5
.github/workflows/release.yml
vendored
@@ -20,10 +20,7 @@ on:
|
||||
type: choice
|
||||
description: Which npm tag should this be published to?
|
||||
options:
|
||||
- latest
|
||||
- next
|
||||
- v5-lts
|
||||
- v4-lts
|
||||
- v7-lts
|
||||
preid:
|
||||
type: choice
|
||||
description: Which prerelease identifier should be used? This is only needed when version is "prepatch", "preminor", "premajor", or "prerelease".
|
||||
|
||||
14
.github/workflows/update-screenshots.yml
vendored
@@ -3,6 +3,20 @@ name: 'Update Reference Screenshots'
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
# Screenshots can be updated for all components or specified component(s).
|
||||
# If the `component` variable is set, then the test has the option to
|
||||
# - run all the instances of the specified component(s) in the `src/components` folder
|
||||
# -- For example: if the `component` value is "item", then the following command will be: `npm run test.e2e item`
|
||||
# - run the specified file path
|
||||
# -- For example: if the `component` value is "src/components/item/test/basic", then the following command will be: `npm run test.e2e src/components/item/test/basic`
|
||||
# - run multiple specified components based on the space-separated value
|
||||
# -- For example: if the `component` value is "item basic", then the following command will be: `npm run test.e2e item basic`
|
||||
# -- For example: if the `component` value is "src/components/item/test/basic src/components/item/test/a11y", then the following command will be: `npm run test.e2e src/components/item/test/basic src/components/item/test/a11y`
|
||||
#
|
||||
# If the `component` variable is not set, then the test will run all the instances of the components in the `src/components` folder.
|
||||
# - For example: `npm run test.e2e`
|
||||
#
|
||||
# More common options can be found at the Playwright Command line page: https://playwright.dev/docs/test-cli
|
||||
component:
|
||||
description: 'What component(s) should be updated? (leave blank to update all or use a space-separated list for multiple components)'
|
||||
required: false
|
||||
|
||||
11
.gitignore
vendored
@@ -68,7 +68,16 @@ core/www/
|
||||
# playwright
|
||||
core/test-results/
|
||||
core/playwright-report/
|
||||
core/**/*-snapshots
|
||||
|
||||
# ground truths generated outside of docker should not be committed to the repo
|
||||
core/**/*-snapshots/*
|
||||
|
||||
# new ground truths should only be generated inside of docker which will result in -linux.png screenshots
|
||||
!core/**/*-snapshots/*-linux.png
|
||||
|
||||
# these files are going to be different per-developer environment so do not add them to the repo
|
||||
core/docker-display.txt
|
||||
core/docker-display-volume.txt
|
||||
|
||||
# angular
|
||||
packages/angular/css/
|
||||
|
||||
1
.vercelignore
Normal file
@@ -0,0 +1 @@
|
||||
core/src/components/**/*/*.png
|
||||
74
CHANGELOG.md
@@ -3,6 +3,80 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.8.6](https://github.com/ionic-team/ionic-framework/compare/v7.8.5...v7.8.6) (2024-04-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **input:** clear button can be navigated using screen reader ([#29366](https://github.com/ionic-team/ionic-framework/issues/29366)) ([#29383](https://github.com/ionic-team/ionic-framework/issues/29383)) ([5ce0c60](https://github.com/ionic-team/ionic-framework/commit/5ce0c609f365aa497814067276b67fc4e58bdb35))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.5](https://github.com/ionic-team/ionic-framework/compare/v7.8.4...v7.8.5) (2024-04-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **modal:** improve sheet modal scrolling and gesture behavior ([#29312](https://github.com/ionic-team/ionic-framework/issues/29312)) ([9738228](https://github.com/ionic-team/ionic-framework/commit/9738228bc05abe3e2012e57b0e6b85f0ec06f66b)), closes [#24583](https://github.com/ionic-team/ionic-framework/issues/24583)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.4](https://github.com/ionic-team/ionic-framework/compare/v7.8.3...v7.8.4) (2024-04-10)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **styles:** compress distributed global stylesheets ([#29275](https://github.com/ionic-team/ionic-framework/issues/29275)) ([b3cd49b](https://github.com/ionic-team/ionic-framework/commit/b3cd49bf2219aacffc1ac34acbae7c76ef243765))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.1](https://github.com/ionic-team/ionic-framework/compare/v7.8.0...v7.8.1) (2024-03-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **datetime:** wheel picker shows consistently in overlays ([#29147](https://github.com/ionic-team/ionic-framework/issues/29147)) ([19c1bc1](https://github.com/ionic-team/ionic-framework/commit/19c1bc16cbc6725463890382365203824b7fd353)), closes [#26234](https://github.com/ionic-team/ionic-framework/issues/26234)
|
||||
* **header:** iOS headers in MD app are not hidden ([#29164](https://github.com/ionic-team/ionic-framework/issues/29164)) ([fdfecd3](https://github.com/ionic-team/ionic-framework/commit/fdfecd32c33c41cf202d3b30c073bfb1b077e2d6)), closes [#28867](https://github.com/ionic-team/ionic-framework/issues/28867)
|
||||
* **react:** avoid definitely typed errors with @types/react@18 ([#29182](https://github.com/ionic-team/ionic-framework/issues/29182)) ([58d217d](https://github.com/ionic-team/ionic-framework/commit/58d217d0cf6b716da855c71c169fb1870d4067d3)), closes [#29178](https://github.com/ionic-team/ionic-framework/issues/29178)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **datetime:** calendar body shows immediately in modal on ios ([#29163](https://github.com/ionic-team/ionic-framework/issues/29163)) ([f759776](https://github.com/ionic-team/ionic-framework/commit/f75977699dae5aeea3d97d4318377633e935afb9)), closes [#24542](https://github.com/ionic-team/ionic-framework/issues/24542)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.8.0](https://github.com/ionic-team/ionic-framework/compare/v7.7.5...v7.8.0) (2024-03-13)
|
||||
|
||||
|
||||
|
||||
@@ -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,79 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.8.6](https://github.com/ionic-team/ionic-framework/compare/v7.8.5...v7.8.6) (2024-04-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **input:** clear button can be navigated using screen reader ([#29366](https://github.com/ionic-team/ionic-framework/issues/29366)) ([#29383](https://github.com/ionic-team/ionic-framework/issues/29383)) ([5ce0c60](https://github.com/ionic-team/ionic-framework/commit/5ce0c609f365aa497814067276b67fc4e58bdb35))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.5](https://github.com/ionic-team/ionic-framework/compare/v7.8.4...v7.8.5) (2024-04-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **modal:** improve sheet modal scrolling and gesture behavior ([#29312](https://github.com/ionic-team/ionic-framework/issues/29312)) ([9738228](https://github.com/ionic-team/ionic-framework/commit/9738228bc05abe3e2012e57b0e6b85f0ec06f66b)), closes [#24583](https://github.com/ionic-team/ionic-framework/issues/24583)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.4](https://github.com/ionic-team/ionic-framework/compare/v7.8.3...v7.8.4) (2024-04-10)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **styles:** compress distributed global stylesheets ([#29275](https://github.com/ionic-team/ionic-framework/issues/29275)) ([b3cd49b](https://github.com/ionic-team/ionic-framework/commit/b3cd49bf2219aacffc1ac34acbae7c76ef243765))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.8.1](https://github.com/ionic-team/ionic-framework/compare/v7.8.0...v7.8.1) (2024-03-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **datetime:** wheel picker shows consistently in overlays ([#29147](https://github.com/ionic-team/ionic-framework/issues/29147)) ([19c1bc1](https://github.com/ionic-team/ionic-framework/commit/19c1bc16cbc6725463890382365203824b7fd353)), closes [#26234](https://github.com/ionic-team/ionic-framework/issues/26234)
|
||||
* **header:** iOS headers in MD app are not hidden ([#29164](https://github.com/ionic-team/ionic-framework/issues/29164)) ([fdfecd3](https://github.com/ionic-team/ionic-framework/commit/fdfecd32c33c41cf202d3b30c073bfb1b077e2d6)), closes [#28867](https://github.com/ionic-team/ionic-framework/issues/28867)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **datetime:** calendar body shows immediately in modal on ios ([#29163](https://github.com/ionic-team/ionic-framework/issues/29163)) ([f759776](https://github.com/ionic-team/ionic-framework/commit/f75977699dae5aeea3d97d4318377633e935afb9)), closes [#24542](https://github.com/ionic-team/ionic-framework/issues/24542)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.8.0](https://github.com/ionic-team/ionic-framework/compare/v7.7.5...v7.8.0) (2024-03-13)
|
||||
|
||||
|
||||
|
||||
5
core/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
# Get Playwright
|
||||
FROM mcr.microsoft.com/playwright:v1.42.1
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /ionic
|
||||
@@ -1158,7 +1158,7 @@ ion-row,shadow
|
||||
|
||||
ion-searchbar,scoped
|
||||
ion-searchbar,prop,animated,boolean,false,false,false
|
||||
ion-searchbar,prop,autocapitalize,string,undefined,true,false
|
||||
ion-searchbar,prop,autocapitalize,string,'default',false,false
|
||||
ion-searchbar,prop,autocomplete,"name" | "email" | "tel" | "url" | "on" | "off" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "photo",'off',false,false
|
||||
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
|
||||
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', arrowBackSharp) as string,false,false
|
||||
|
||||
799
core/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.8.0",
|
||||
"version": "7.8.6",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -54,12 +54,13 @@
|
||||
"@types/node": "^14.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
||||
"@typescript-eslint/parser": "^6.7.2",
|
||||
"chalk": "^5.3.0",
|
||||
"clean-css-cli": "^5.6.1",
|
||||
"domino": "^2.1.6",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-custom-rules": "file:custom-rules",
|
||||
"execa": "^5.0.0",
|
||||
"execa": "^8.0.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-cli": "^29.7.0",
|
||||
@@ -77,7 +78,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",
|
||||
@@ -94,7 +95,11 @@
|
||||
"test.e2e.update-snapshots": "npm run test.e2e -- --update-snapshots",
|
||||
"test.watch": "jest --watch --no-cache",
|
||||
"test.treeshake": "node scripts/treeshaking.js dist/index.js",
|
||||
"validate": "npm run lint && npm run test && npm run build && npm run test.treeshake"
|
||||
"validate": "npm run lint && npm run test && npm run build && npm run test.treeshake",
|
||||
"docker.build": "docker build -t ionic-playwright .",
|
||||
"test.e2e.docker": "npm run docker.build && node ./scripts/docker.mjs",
|
||||
"test.e2e.docker.update-snapshots": "npm run test.e2e.docker -- --update-snapshots",
|
||||
"test.e2e.docker.ci": "npm run docker.build && CI=true node ./scripts/docker.mjs"
|
||||
},
|
||||
"author": "Ionic Team",
|
||||
"license": "MIT",
|
||||
|
||||
56
core/scripts/docker.mjs
Normal file
@@ -0,0 +1,56 @@
|
||||
import { execa } from 'execa';
|
||||
import * as fs from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import chalk from 'chalk';
|
||||
|
||||
const removeNewline = (string) => {
|
||||
return string.replace(/(\r\n|\n|\r)/gm, "");
|
||||
}
|
||||
|
||||
const readConfigFile = (file) => {
|
||||
if (fs.existsSync(file)) {
|
||||
return fs.readFileSync(file, { encoding: 'utf-8' });
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// These files are optional, so we don't want to error if they don't exist
|
||||
const display = removeNewline(readConfigFile('docker-display.txt'));
|
||||
const displayVolume = removeNewline(readConfigFile('docker-display-volume.txt'));
|
||||
|
||||
// Using --mount requires an absolute path which is what this gives us.
|
||||
const pwd = resolve('./');
|
||||
|
||||
/**
|
||||
* -it will let the user gracefully kill the process using Ctrl+C (or equivalent)
|
||||
* -e DISPLAY and -v handle configuration for headed mode
|
||||
* --ipc=host is recommended when using Chromium to avoid out of memory crashes: https://playwright.dev/docs/ci#docker
|
||||
* --init is recommended to avoid zombie processes: https://playwright.dev/docs/ci#docker
|
||||
* --mount allow us to mount the local Ionic project inside of the Docker container so devs do not need to re-build the project in Docker.
|
||||
*/
|
||||
const args = ['run', '--rm', '--init', `-e DISPLAY=${display}`, `-v ${displayVolume}`, '--ipc=host', `--mount=type=bind,source=${pwd},target=/ionic`, 'ionic-playwright', 'npm run test.e2e --', ...process.argv.slice(2)];
|
||||
|
||||
// Set the CI env variable so Playwright uses the CI config
|
||||
if (process.env.CI) {
|
||||
args.splice(1, 0, '-e CI=true');
|
||||
/**
|
||||
* Otherwise, we should let the session be interactive locally. This will
|
||||
* not work on CI which is why we do not apply it there.
|
||||
*/
|
||||
} else {
|
||||
args.splice(1, 0, '-it');
|
||||
}
|
||||
|
||||
/**
|
||||
* While these config files are optional to run the tests, they are required to run
|
||||
* the tests in headed mode. Add a warning if dev tries to run headed tests without
|
||||
* the correct config files.
|
||||
*/
|
||||
const requestHeaded = process.argv.find(arg => arg.includes('headed'));
|
||||
const hasHeadedConfigFiles = display && displayVolume;
|
||||
if (requestHeaded && !hasHeadedConfigFiles) {
|
||||
console.warn(chalk.yellow.bold('\n⚠️ You are running tests in headed mode, but one or more of your headed config files was not found.\nPlease ensure that both docker-display.txt and docker-display-volume.txt have been created in the correct location.\n'));
|
||||
}
|
||||
|
||||
execa('docker', args, { shell: true, stdio: 'inherit' });
|
||||
@@ -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).
|
||||
|
||||
6
core/src/components.d.ts
vendored
@@ -3211,7 +3211,7 @@ export namespace Components {
|
||||
}
|
||||
interface IonToggle {
|
||||
/**
|
||||
* How to control the alignment of the toggle and label on the cross axis. ``"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
|
||||
* How to control the alignment of the toggle and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
|
||||
*/
|
||||
"alignment": 'start' | 'center';
|
||||
/**
|
||||
@@ -7295,7 +7295,7 @@ declare namespace LocalJSX {
|
||||
/**
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
||||
*/
|
||||
"autocapitalize": string;
|
||||
"autocapitalize"?: string;
|
||||
/**
|
||||
* Set the input's autocomplete property.
|
||||
*/
|
||||
@@ -8037,7 +8037,7 @@ declare namespace LocalJSX {
|
||||
}
|
||||
interface IonToggle {
|
||||
/**
|
||||
* How to control the alignment of the toggle and label on the cross axis. ``"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
|
||||
* How to control the alignment of the toggle and label on the cross axis. `"start"`: The label and control will appear on the left of the cross axis in LTR, and on the right side in RTL. `"center"`: The label and control will appear at the center of the cross axis in both LTR and RTL.
|
||||
*/
|
||||
"alignment"?: 'start' | 'center';
|
||||
/**
|
||||
|
||||
@@ -288,6 +288,10 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
await alert.evaluate((el: HTMLIonAlertElement) => el.present());
|
||||
await ionAlertDidPresent.next();
|
||||
|
||||
/**
|
||||
* The borders on the text fields may not be visible in the screenshot
|
||||
* when using Safari, this is due to a WebKit rendering quirk.
|
||||
*/
|
||||
await expect(page).toHaveScreenshot(screenshot(`alert-text-fields-scale`));
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
@@ -212,3 +212,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))};
|
||||
}
|
||||
|
||||
@@ -160,3 +160,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))};
|
||||
}
|
||||
|
||||
@@ -331,11 +331,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: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
@@ -108,6 +108,7 @@ export class Datetime implements ComponentInterface {
|
||||
private calendarBodyRef?: HTMLElement;
|
||||
private monthYearToggleItemRef?: HTMLIonItemElement;
|
||||
private popoverRef?: HTMLIonPopoverElement;
|
||||
private intersectionTrackerRef?: HTMLElement;
|
||||
private clearFocusVisible?: () => void;
|
||||
private parsedMinuteValues?: number[];
|
||||
private parsedHourValues?: number[];
|
||||
@@ -1079,6 +1080,8 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
const { el, intersectionTrackerRef } = this;
|
||||
|
||||
/**
|
||||
* If a scrollable element is hidden using `display: none`,
|
||||
* it will not have a scroll height meaning we cannot scroll elements
|
||||
@@ -1106,7 +1109,7 @@ export class Datetime implements ComponentInterface {
|
||||
this.el.classList.add('datetime-ready');
|
||||
});
|
||||
};
|
||||
const visibleIO = new IntersectionObserver(visibleCallback, { threshold: 0.01 });
|
||||
const visibleIO = new IntersectionObserver(visibleCallback, { threshold: 0.01, root: el });
|
||||
|
||||
/**
|
||||
* Use raf to avoid a race condition between the component loading and
|
||||
@@ -1114,7 +1117,7 @@ export class Datetime implements ComponentInterface {
|
||||
* could cause the datetime to start at a visibility of 0, erroneously
|
||||
* triggering the `hiddenIO` observer below.
|
||||
*/
|
||||
raf(() => visibleIO?.observe(this.el));
|
||||
raf(() => visibleIO?.observe(intersectionTrackerRef!));
|
||||
|
||||
/**
|
||||
* We need to clean up listeners when the datetime is hidden
|
||||
@@ -1144,8 +1147,8 @@ export class Datetime implements ComponentInterface {
|
||||
this.el.classList.remove('datetime-ready');
|
||||
});
|
||||
};
|
||||
const hiddenIO = new IntersectionObserver(hiddenCallback, { threshold: 0 });
|
||||
raf(() => hiddenIO?.observe(this.el));
|
||||
const hiddenIO = new IntersectionObserver(hiddenCallback, { threshold: 0, root: el });
|
||||
raf(() => hiddenIO?.observe(intersectionTrackerRef!));
|
||||
|
||||
/**
|
||||
* Datetime uses Ionic components that emit
|
||||
@@ -2613,6 +2616,20 @@ export class Datetime implements ComponentInterface {
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{/*
|
||||
WebKit has a quirk where IntersectionObserver callbacks are delayed until after
|
||||
an accelerated animation finishes if the "root" specified in the config is the
|
||||
browser viewport (the default behavior if "root" is not specified). This means
|
||||
that when presenting a datetime in a modal on iOS the calendar body appears
|
||||
blank until the modal animation finishes.
|
||||
|
||||
We can work around this by observing .intersection-tracker and using the host
|
||||
(ion-datetime) as the "root". This allows the IO callback to fire the moment
|
||||
the datetime is visible. The .intersection-tracker element should not have
|
||||
dimensions or additional styles, and it should not be positioned absolutely
|
||||
otherwise the IO callback may fire at unexpected times.
|
||||
*/}
|
||||
<div class="intersection-tracker" ref={(el) => (this.intersectionTrackerRef = el)}></div>
|
||||
{this.renderDatetime(mode)}
|
||||
</Host>
|
||||
);
|
||||
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
@@ -132,8 +132,11 @@
|
||||
* We use opacity: 0 to avoid a layout shift.
|
||||
* We target both the attribute and the class in the event that the attribute
|
||||
* is not reflected on the host in some frameworks.
|
||||
*
|
||||
* Both headers should be scoped to iOS mode otherwise an MD app that uses an
|
||||
* iOS header may cause other MD headers to be unexpectedly hidden.
|
||||
*/
|
||||
ion-header:not(.header-collapse-main):has(~ ion-content ion-header[collapse="condense"],
|
||||
~ ion-content ion-header.header-collapse-condense) {
|
||||
ion-header.header-ios:not(.header-collapse-main):has(~ ion-content ion-header.header-ios[collapse="condense"],
|
||||
~ ion-content ion-header.header-ios.header-collapse-condense) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -85,3 +85,91 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, c
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This test only impacts MD applications
|
||||
*/
|
||||
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('header: translucent'), () => {
|
||||
test('should not hide MD headers when using a descendant iOS header in an MD app', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/28867',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header id="main-header">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-header mode="ios">
|
||||
<ion-toolbar>
|
||||
<ion-title>Welcome</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const header = page.locator('ion-header#main-header');
|
||||
|
||||
/**
|
||||
* The existence of the iOS header in an MD app should not cause the main MD header
|
||||
* to be hidden. We do not have toHaveVisible because the behavior that hides
|
||||
* the header under correct circumstances does it using opacity: 0.
|
||||
* Playwright considers an element with opacity: 0 to still be visible
|
||||
* because it has a non-zero bounding box.
|
||||
*/
|
||||
await expect(header).toHaveScreenshot(screenshot('header-md-visibility-ios-descendant'));
|
||||
});
|
||||
test('should not hide MD headers when using a root iOS header in an MD app', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/28867',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-header id="main-header" mode="ios">
|
||||
<ion-toolbar>
|
||||
<ion-title>Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">Header</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Welcome</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-content>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const header = page.locator('ion-header#main-header');
|
||||
|
||||
/**
|
||||
* The existence of the iOS header in an MD app should not cause the main MD header
|
||||
* to be hidden. We do not have toHaveVisible because the behavior that hides
|
||||
* the header under correct circumstances does it using opacity: 0.
|
||||
* Playwright considers an element with opacity: 0 to still be visible
|
||||
* because it has a non-zero bounding box.
|
||||
*/
|
||||
await expect(header).toHaveScreenshot(screenshot('header-md-visibility-ios-main'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
@@ -831,6 +831,15 @@ export class Input implements ComponentInterface {
|
||||
*/
|
||||
ev.preventDefault();
|
||||
}}
|
||||
onFocusin={(ev) => {
|
||||
/**
|
||||
* Prevent the focusin event from bubbling otherwise it will cause the focusin
|
||||
* event listener in scroll assist to fire. When this fires, focus will be moved
|
||||
* back to the input even if the clear button was never tapped. This poses issues
|
||||
* for screen readers as it means users would be unable to swipe past the clear button.
|
||||
*/
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
onClick={this.clearTextInput}
|
||||
>
|
||||
<ion-icon aria-hidden="true" icon={mode === 'ios' ? closeCircle : closeSharp}></ion-icon>
|
||||
|
||||
@@ -12,165 +12,6 @@
|
||||
<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>
|
||||
|
||||
<style>
|
||||
/*
|
||||
* Dark Colors
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
body.dark {
|
||||
--ion-color-primary: #428cff;
|
||||
--ion-color-primary-rgb: 66, 140, 255;
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-primary-shade: #3a7be0;
|
||||
--ion-color-primary-tint: #5598ff;
|
||||
|
||||
--ion-color-secondary: #50c8ff;
|
||||
--ion-color-secondary-rgb: 80, 200, 255;
|
||||
--ion-color-secondary-contrast: #ffffff;
|
||||
--ion-color-secondary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-secondary-shade: #46b0e0;
|
||||
--ion-color-secondary-tint: #62ceff;
|
||||
|
||||
--ion-color-tertiary: #6a64ff;
|
||||
--ion-color-tertiary-rgb: 106, 100, 255;
|
||||
--ion-color-tertiary-contrast: #ffffff;
|
||||
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-tertiary-shade: #5d58e0;
|
||||
--ion-color-tertiary-tint: #7974ff;
|
||||
|
||||
--ion-color-success: #2fdf75;
|
||||
--ion-color-success-rgb: 47, 223, 117;
|
||||
--ion-color-success-contrast: #000000;
|
||||
--ion-color-success-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-success-shade: #29c467;
|
||||
--ion-color-success-tint: #44e283;
|
||||
|
||||
--ion-color-warning: #ffd534;
|
||||
--ion-color-warning-rgb: 255, 213, 52;
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-warning-shade: #e0bb2e;
|
||||
--ion-color-warning-tint: #ffd948;
|
||||
|
||||
--ion-color-danger: #ff4961;
|
||||
--ion-color-danger-rgb: 255, 73, 97;
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-danger-shade: #e04055;
|
||||
--ion-color-danger-tint: #ff5b71;
|
||||
|
||||
--ion-color-dark: #f4f5f8;
|
||||
--ion-color-dark-rgb: 244, 245, 248;
|
||||
--ion-color-dark-contrast: #000000;
|
||||
--ion-color-dark-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-dark-shade: #d7d8da;
|
||||
--ion-color-dark-tint: #f5f6f9;
|
||||
|
||||
--ion-color-medium: #989aa2;
|
||||
--ion-color-medium-rgb: 152, 154, 162;
|
||||
--ion-color-medium-contrast: #000000;
|
||||
--ion-color-medium-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-medium-shade: #86888f;
|
||||
--ion-color-medium-tint: #a2a4ab;
|
||||
|
||||
--ion-color-light: #222428;
|
||||
--ion-color-light-rgb: 34, 36, 40;
|
||||
--ion-color-light-contrast: #ffffff;
|
||||
--ion-color-light-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-light-shade: #1e2023;
|
||||
--ion-color-light-tint: #383a3e;
|
||||
}
|
||||
|
||||
/*
|
||||
* iOS Dark Theme
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
.ios body.dark {
|
||||
--ion-background-color: #000000;
|
||||
--ion-background-color-rgb: 0, 0, 0;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-color-step-50: #0d0d0d;
|
||||
--ion-color-step-100: #1a1a1a;
|
||||
--ion-color-step-150: #262626;
|
||||
--ion-color-step-200: #333333;
|
||||
--ion-color-step-250: #404040;
|
||||
--ion-color-step-300: #4d4d4d;
|
||||
--ion-color-step-350: #595959;
|
||||
--ion-color-step-400: #666666;
|
||||
--ion-color-step-450: #737373;
|
||||
--ion-color-step-500: #808080;
|
||||
--ion-color-step-550: #8c8c8c;
|
||||
--ion-color-step-600: #999999;
|
||||
--ion-color-step-650: #a6a6a6;
|
||||
--ion-color-step-700: #b3b3b3;
|
||||
--ion-color-step-750: #bfbfbf;
|
||||
--ion-color-step-800: #cccccc;
|
||||
--ion-color-step-850: #d9d9d9;
|
||||
--ion-color-step-900: #e6e6e6;
|
||||
--ion-color-step-950: #f2f2f2;
|
||||
|
||||
--ion-item-background: #000000;
|
||||
|
||||
--ion-card-background: #1c1c1d;
|
||||
}
|
||||
|
||||
.ios body.dark ion-modal {
|
||||
--ion-background-color: var(--ion-color-step-100);
|
||||
--ion-toolbar-background: var(--ion-color-step-150);
|
||||
--ion-toolbar-border-color: var(--ion-color-step-250);
|
||||
--ion-item-background: var(--ion-color-step-150);
|
||||
}
|
||||
|
||||
/*
|
||||
* Material Design Dark Theme
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
.md body.dark {
|
||||
--ion-background-color: #121212;
|
||||
--ion-background-color-rgb: 18, 18, 18;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-border-color: #222222;
|
||||
|
||||
--ion-color-step-50: #1e1e1e;
|
||||
--ion-color-step-100: #2a2a2a;
|
||||
--ion-color-step-150: #363636;
|
||||
--ion-color-step-200: #414141;
|
||||
--ion-color-step-250: #4d4d4d;
|
||||
--ion-color-step-300: #595959;
|
||||
--ion-color-step-350: #656565;
|
||||
--ion-color-step-400: #717171;
|
||||
--ion-color-step-450: #7d7d7d;
|
||||
--ion-color-step-500: #898989;
|
||||
--ion-color-step-550: #949494;
|
||||
--ion-color-step-600: #a0a0a0;
|
||||
--ion-color-step-650: #acacac;
|
||||
--ion-color-step-700: #b8b8b8;
|
||||
--ion-color-step-750: #c4c4c4;
|
||||
--ion-color-step-800: #d0d0d0;
|
||||
--ion-color-step-850: #dbdbdb;
|
||||
--ion-color-step-900: #e7e7e7;
|
||||
--ion-color-step-950: #f3f3f3;
|
||||
|
||||
--ion-item-background: #1e1e1e;
|
||||
|
||||
--ion-toolbar-background: #1f1f1f;
|
||||
|
||||
--ion-tab-bar-background: #1f1f1f;
|
||||
|
||||
--ion-card-background: #1e1e1e;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -347,12 +188,6 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// TODO FW-4005
|
||||
const params = new URL(window.location).searchParams;
|
||||
const dark = params.get('dark');
|
||||
if (dark !== null) {
|
||||
document.body.classList.add('dark');
|
||||
}
|
||||
const attach = document.getElementById('attachClick');
|
||||
|
||||
attach.addEventListener('click', (ev) => {
|
||||
|
||||
@@ -19,14 +19,34 @@ configs().forEach(({ title, screenshot, config }) => {
|
||||
});
|
||||
});
|
||||
|
||||
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
configs({ directions: ['ltr'], themes: ['dark'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('item: buttons dark'), () => {
|
||||
test('should not have visual regressions in dark', async ({ page }) => {
|
||||
await page.goto(`/src/components/item/test/buttons?dark=true`, config);
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/27130',
|
||||
});
|
||||
|
||||
await page.setIonViewport();
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-list>
|
||||
<ion-item button="true">
|
||||
<ion-label>Button Item</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button="true" class="ion-activated">
|
||||
<ion-label>Activated Button Item</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button="true" class="ion-focused">
|
||||
<ion-label>Focused Button Item</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await expect(page).toHaveScreenshot(screenshot(`item-buttons-dark-diff`));
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot(`item-buttons-dark-diff`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
@@ -1,5 +1,6 @@
|
||||
import { isIonContent, findClosestIonContent } from '@utils/content';
|
||||
import { createGesture } from '@utils/gesture';
|
||||
import { clamp, raf } from '@utils/helpers';
|
||||
import { clamp, raf, getElementRoot } from '@utils/helpers';
|
||||
|
||||
import type { Animation } from '../../../interface';
|
||||
import type { GestureDetail } from '../../../utils/gesture';
|
||||
@@ -142,22 +143,35 @@ export const createSheetGesture = (
|
||||
|
||||
const canStart = (detail: GestureDetail) => {
|
||||
/**
|
||||
* If the sheet is fully expanded and
|
||||
* the user is swiping on the content,
|
||||
* the gesture should not start to
|
||||
* allow for scrolling on the content.
|
||||
* If we are swiping on the content, swiping should only be possible if the content
|
||||
* is scrolled all the way to the top so that we do not interfere with scrolling.
|
||||
*
|
||||
* We cannot assume that the `ion-content` target will remain consistent between swipes.
|
||||
* For example, when using ion-nav within a modal it is possible to swipe, push a view,
|
||||
* and then swipe again. The target content will not be the same between swipes.
|
||||
*/
|
||||
const content = (detail.event.target! as HTMLElement).closest('ion-content');
|
||||
const contentEl = findClosestIonContent(detail.event.target! as HTMLElement);
|
||||
currentBreakpoint = getCurrentBreakpoint();
|
||||
|
||||
if (currentBreakpoint === 1 && content) {
|
||||
return false;
|
||||
if (currentBreakpoint === 1 && contentEl) {
|
||||
/**
|
||||
* The modal should never swipe to close on the content with a refresher.
|
||||
* Note 1: We cannot solve this by making this gesture have a higher priority than
|
||||
* the refresher gesture as the iOS native refresh gesture uses a scroll listener in
|
||||
* addition to a gesture.
|
||||
*
|
||||
* Note 2: Do not use getScrollElement here because we need this to be a synchronous
|
||||
* operation, and getScrollElement is asynchronous.
|
||||
*/
|
||||
const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
|
||||
const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
|
||||
return !hasRefresherInContent && scrollEl!.scrollTop === 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const onStart = () => {
|
||||
const onStart = (detail: GestureDetail) => {
|
||||
/**
|
||||
* If canDismiss is anything other than `true`
|
||||
* then users should be able to swipe down
|
||||
@@ -173,11 +187,10 @@ export const createSheetGesture = (
|
||||
canDismissBlocksGesture = baseEl.canDismiss !== undefined && baseEl.canDismiss !== true && minBreakpoint === 0;
|
||||
|
||||
/**
|
||||
* If swiping on the content
|
||||
* we should disable scrolling otherwise
|
||||
* the sheet will expand and the content will scroll.
|
||||
* If we are pulling down, then it is possible we are pulling on the content.
|
||||
* We do not want scrolling to happen at the same time as the gesture.
|
||||
*/
|
||||
if (contentEl) {
|
||||
if (detail.deltaY > 0 && contentEl) {
|
||||
contentEl.scrollY = false;
|
||||
}
|
||||
|
||||
@@ -193,6 +206,16 @@ export const createSheetGesture = (
|
||||
};
|
||||
|
||||
const onMove = (detail: GestureDetail) => {
|
||||
/**
|
||||
* If we are pulling down, then it is possible we are pulling on the content.
|
||||
* We do not want scrolling to happen at the same time as the gesture.
|
||||
* This accounts for when the user scrolls down, scrolls all the way up, and then
|
||||
* pulls down again such that the modal should start to move.
|
||||
*/
|
||||
if (detail.deltaY > 0 && contentEl) {
|
||||
contentEl.scrollY = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the change in gesture position on the Y axis,
|
||||
* compute where the offset of the animation should be
|
||||
@@ -314,6 +337,17 @@ export const createSheetGesture = (
|
||||
onDismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the sheet is going to be fully expanded then we should enable
|
||||
* scrolling immediately. The sheet modal animation takes ~500ms to finish
|
||||
* so if we wait until then there is a visible delay for when scrolling is
|
||||
* re-enabled. Native iOS allows for scrolling on the sheet modal as soon
|
||||
* as the gesture is released, so we align with that.
|
||||
*/
|
||||
if (contentEl && snapToBreakpoint === breakpoints[breakpoints.length - 1]) {
|
||||
contentEl.scrollY = true;
|
||||
}
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
animation
|
||||
.onFinish(
|
||||
@@ -334,14 +368,6 @@ export const createSheetGesture = (
|
||||
currentBreakpoint = snapToBreakpoint;
|
||||
onBreakpointChange(currentBreakpoint);
|
||||
|
||||
/**
|
||||
* If the sheet is fully expanded, we can safely
|
||||
* enable scrolling again.
|
||||
*/
|
||||
if (contentEl && currentBreakpoint === breakpoints[breakpoints.length - 1]) {
|
||||
contentEl.scrollY = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backdrop should become enabled
|
||||
* after the backdropBreakpoint value
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 38 KiB |
@@ -92,7 +92,11 @@ export class PickerColumnInternal implements ComponentInterface {
|
||||
*/
|
||||
componentWillLoad() {
|
||||
const visibleCallback = (entries: IntersectionObserverEntry[]) => {
|
||||
const ev = entries[0];
|
||||
/**
|
||||
* Browsers will sometimes group multiple IO events into a single callback.
|
||||
* As a result, we want to grab the last/most recent event in case there are multiple events.
|
||||
*/
|
||||
const ev = entries[entries.length - 1];
|
||||
|
||||
if (ev.isIntersecting) {
|
||||
const { activeItem, el } = this;
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Nested Popovers
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
@@ -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 }) => {
|
||||
|
||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
@@ -84,20 +84,19 @@ export class Searchbar implements ComponentInterface {
|
||||
* and disabled by default on Android
|
||||
* for Searchbar. The autocapitalize type on HTMLElement
|
||||
* requires that it be a string and never undefined.
|
||||
* However, setting it to a string value would be a breaking change
|
||||
* in behavior, so we use "!" to tell TypeScript that this property
|
||||
* is always defined so we can rely on the browser defaults. Browsers
|
||||
* will automatically set a default value if the developer does not set one.
|
||||
* However, setting it to one of the accepted values would be a breaking change
|
||||
* in behavior, so we use the internal "default" keyword to ensure
|
||||
* we use the default browser behavior for now.
|
||||
*
|
||||
* In the future, this property will default to "off" to align with
|
||||
* Input and Textarea, and the "!" will not be needed.
|
||||
* Input and Textarea, and the internal "default" keyword will not be needed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
||||
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
||||
*/
|
||||
@Prop() autocapitalize!: string;
|
||||
@Prop() autocapitalize: string = 'default';
|
||||
|
||||
/**
|
||||
* Set the input's autocomplete property.
|
||||
@@ -621,7 +620,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);
|
||||
@@ -683,7 +682,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}
|
||||
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |