Compare commits

..

29 Commits

Author SHA1 Message Date
ionitron
ffe5307905 v7.2.4 2023-08-16 13:26:09 +00:00
Ryan Waskiewicz
d3e82c99b8 chore(ci): ensure stencil nightly gets installed for spec tests (#27974)
Issue number: #

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Stencil v3.4 is being used in the nightly run of these tests

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

this commit updates the `test-core-spec` action to accept an argument
for the version of stencil that should be installed/used. since we do
not (and arguably, should not) cache `node_modules/`, we need a way to
inform this action that a nightly version of stencil should be installed

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information


I fully expect nightly CI to begin to fail as a result of merging this.
We'll fix that next week (in Stencil)
<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-15 15:33:22 +00:00
Maria Hutt
eafa7b5dc6 test(many): gestures flakiness (#27808)
Issue number: multiple internals

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Multiple tests that use gestures are flaky on GitHub. Due to that those
tests are being skipped.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- `page.mouse.move` will not work as expected if it the mouse moves
outside of the viewport. This may lead to events to not fire every time.
There's now a check to determine if the coordinates are valid. If they
are not, then it will update the coordinates to be as close to the
viewport's edge instead of being outside.
- Safari doesn't repaint the frame as often as the other browsers. This
causes the tests on GitHub to appear to be lagging. Now the frame is
forced to repaint only for Safari.
- Most tests are no longer being skipped.
- Range is still having issues on GitHub. It is no longer flaky locally
with the changes in this PR. I've had to revert them back to skip until
further notice.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

If this PR is merged, then:
- FW-3006, FW-2795, and FW-3079 can be closed
- FW-4556 still needs to remain open since range is still flaky on
GitHub

---------

Co-authored-by: ionitron <hi@ionicframework.com>
Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
2023-08-14 20:12:04 +00:00
Liam DeBeasi
92b13c298b chore: highlight variables are deprecated (#27987)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

There was some confusion on
https://github.com/ionic-team/ionic-framework/issues/27985 as to how the
`--highlight-*` variables on `ion-item` apply to the modern form
controls. These variables only work with the legacy form syntax, but we
did not add a proper deprecation message.

`--highlight-*` variables have been added to `ion-input` and
`ion-textarea` instead so developers can customize the highlight when
using the modern form syntax.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Deprecated the `--highlight-*` variables on `ion-item`.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-14 15:16:05 +00:00
dependabot[bot]
e5a02f49e5 chore(deps-dev): Bump @playwright/test from 1.36.2 to 1.37.0 in /core (#27977)
Bumps [@playwright/test](https://github.com/Microsoft/playwright) from
1.36.2 to 1.37.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Microsoft/playwright/releases"><code>@​playwright/test</code>'s
releases</a>.</em></p>
<blockquote>
<h2>v1.37.0</h2>
<h2> New tool to merge reports</h2>
<p>If you run tests on multiple shards, you can now merge all reports in
a single HTML report (or any other report)
using the new <code>merge-reports</code> CLI tool.</p>
<p>Using <code>merge-reports</code> tool requires the following
steps:</p>
<ol>
<li>
<p>Adding a new &quot;blob&quot; reporter to the config when running on
CI:</p>
<pre lang="js"
data-meta="title=&quot;playwright.config.ts&quot;"><code>export default
defineConfig({
  testDir: './tests',
  reporter: process.env.CI ? 'blob' : 'html',
});
</code></pre>
<p>The &quot;blob&quot; reporter will produce &quot;.zip&quot; files
that contain all the information
about the test run.</p>
</li>
<li>
<p>Copying all &quot;blob&quot; reports in a single shared location and
running <code>npx playwright merge-reports</code>:</p>
<pre lang="bash"><code>npx playwright merge-reports --reporter html
./all-blob-reports
</code></pre>
</li>
</ol>
<p>Read more in <a href="https://playwright.dev/docs/test-sharding">our
documentation</a>.</p>
<h2>📚 Debian 12 Bookworm Support</h2>
<p>Playwright now supports Debian 12 Bookworm on both x86_64 and arm64
for Chromium, Firefox and WebKit.
Let us know if you encounter any issues!</p>
<p>Linux support looks like this:</p>
<table>
<thead>
<tr>
<th align="left"></th>
<th align="center">Ubuntu 20.04</th>
<th align="center">Ubuntu 22.04</th>
<th align="center">Debian 11</th>
<th align="center">Debian 12</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Chromium</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="left">WebKit</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="left">Firefox</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody>
</table>
<h2>🌈 UI Mode Updates</h2>
<ul>
<li>UI Mode now respects project dependencies. You can control which
dependencies to respect by checking/unchecking them in a projects
list.</li>
<li>Console logs from the test are now displayed in the Console
tab.</li>
</ul>
<h2>Browser Versions</h2>
<ul>
<li>Chromium 116.0.5845.82</li>
<li>Mozilla Firefox 115.0</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2c9e02a800"><code>2c9e02a</code></a>
chore: mark 1.37.0 (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26410">#26410</a>)</li>
<li><a
href="37ba0b657d"><code>37ba0b6</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26411">#26411</a>):
docs: add release notes for js v1.37</li>
<li><a
href="9a5172e6c1"><code>9a5172e</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26413">#26413</a>):
fix(merge): allow reports with same name as input (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26417">#26417</a>)</li>
<li><a
href="eed73de573"><code>eed73de</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26400">#26400</a>):
feat(chromium): roll to r1076 (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26403">#26403</a>)</li>
<li><a
href="7999841a19"><code>7999841</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26390">#26390</a>):
chore: allow merging defineConfig</li>
<li><a
href="56b22fa0b1"><code>56b22fa</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26380">#26380</a>):
devops(merge): authorize service principal by us… (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26384">#26384</a>)</li>
<li><a
href="421bffb7d7"><code>421bffb</code></a>
cherry-pick(<a
href="https://redirect.github.com/Microsoft/playwright/issues/26382">#26382</a>):
docs(merge): use azcopy for uploads (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26383">#26383</a>)</li>
<li><a
href="ff0aef37f8"><code>ff0aef3</code></a>
devops: use azcopy for better upload performance (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26360">#26360</a>)</li>
<li><a
href="65ac0d5256"><code>65ac0d5</code></a>
chore: add k8s grid deployments (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26359">#26359</a>)</li>
<li><a
href="ffd6cf60eb"><code>ffd6cf6</code></a>
fix: eliminate race in compilation cache (<a
href="https://redirect.github.com/Microsoft/playwright/issues/26353">#26353</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/Microsoft/playwright/compare/v1.36.2...v1.37.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@playwright/test&package-manager=npm_and_yarn&previous-version=1.36.2&new-version=1.37.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ionitron <hi@ionicframework.com>
2023-08-14 14:34:47 +00:00
dependabot[bot]
8d22874b79 chore(deps-dev): Bump @capacitor/core from 5.2.2 to 5.2.3 in /core (#27978)
Bumps [@capacitor/core](https://github.com/ionic-team/capacitor) from
5.2.2 to 5.2.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ionic-team/capacitor/releases"><code>@​capacitor/core</code>'s
releases</a>.</em></p>
<blockquote>
<h2>5.2.3</h2>
<h2><a
href="https://github.com/ionic-team/capacitor/compare/5.2.2...5.2.3">5.2.3</a>
(2023-08-10)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>android:</strong> allow single input file selection from
samsumg gallery (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6778">#6778</a>)
(<a
href="3d57ecdf76">3d57ecd</a>)</li>
<li><strong>android:</strong> avoid R8 optimizations remove plugin
classes (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6783">#6783</a>)
(<a
href="cc85df5f3a">cc85df5</a>)</li>
<li><strong>cli:</strong> remove package related checks on doctor
command (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6773">#6773</a>)
(<a
href="4499b6bb6c">4499b6b</a>)</li>
<li><strong>cli:</strong> signing type option issue (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6716">#6716</a>)
(<a
href="ee0f7457e4">ee0f745</a>)</li>
<li><strong>cookies:</strong> hide httpOnly cookies from client (<a
href="0cc927ef5f">0cc927e</a>)</li>
<li><strong>http:</strong> return valid response for relative url xhr
requests (<a
href="bde6569621">bde6569</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ionic-team/capacitor/blob/main/CHANGELOG.md"><code>@​capacitor/core</code>'s
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/ionic-team/capacitor/compare/5.2.2...5.2.3">5.2.3</a>
(2023-08-10)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>android:</strong> allow single input file selection from
samsumg gallery (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6778">#6778</a>)
(<a
href="3d57ecdf76">3d57ecd</a>)</li>
<li><strong>android:</strong> avoid R8 optimizations remove plugin
classes (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6783">#6783</a>)
(<a
href="cc85df5f3a">cc85df5</a>)</li>
<li><strong>cli:</strong> remove package related checks on doctor
command (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6773">#6773</a>)
(<a
href="4499b6bb6c">4499b6b</a>)</li>
<li><strong>cli:</strong> signing type option issue (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6716">#6716</a>)
(<a
href="ee0f7457e4">ee0f745</a>)</li>
<li><strong>cookies:</strong> hide httpOnly cookies from client (<a
href="0cc927ef5f">0cc927e</a>)</li>
<li><strong>http:</strong> return valid response for relative url xhr
requests (<a
href="bde6569621">bde6569</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="26f2ccdb44"><code>26f2ccd</code></a>
Release 5.2.3</li>
<li><a
href="61d3ab85dd"><code>61d3ab8</code></a>
chore: update workspaces entries (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6805">#6805</a>)</li>
<li><a
href="bde6569621"><code>bde6569</code></a>
fix(http): return valid response for relative url xhr requests</li>
<li><a
href="0cc927ef5f"><code>0cc927e</code></a>
fix(cookies): hide httpOnly cookies from client</li>
<li><a
href="4583c57b22"><code>4583c57</code></a>
chore(readme): add new contributor (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6788">#6788</a>)</li>
<li><a
href="ee0f7457e4"><code>ee0f745</code></a>
fix(cli): signing type option issue (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6716">#6716</a>)</li>
<li><a
href="cc85df5f3a"><code>cc85df5</code></a>
fix(android): avoid R8 optimizations remove plugin classes (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6783">#6783</a>)</li>
<li><a
href="3d57ecdf76"><code>3d57ecd</code></a>
fix(android): allow single input file selection from samsumg gallery (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6778">#6778</a>)</li>
<li><a
href="4499b6bb6c"><code>4499b6b</code></a>
fix(cli): remove package related checks on doctor command (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6773">#6773</a>)</li>
<li><a
href="88f03d9ef9"><code>88f03d9</code></a>
chore: update lerna (<a
href="https://redirect.github.com/ionic-team/capacitor/issues/6731">#6731</a>)</li>
<li>See full diff in <a
href="https://github.com/ionic-team/capacitor/compare/5.2.2...5.2.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@capacitor/core&package-manager=npm_and_yarn&previous-version=5.2.2&new-version=5.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 14:20:18 +00:00
Liam DeBeasi
8fa12fc888 fix(title): large title aligns with ios spec (#27969)
Issue number: resolves #27966

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

The large title on iOS added bottom padding to create space between the
title and the main content. However, this caused tall text to be cut off
on the top.

During development I also noticed that the padding value we were using
does not match the iOS spec.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- The padding is now applied to the toolbar that contains the large
title. The title itself is positioned absolutely so adding
padding/margin to it never actually had the desired effect. What we want
is space between the title and any content in sibling toolbars. All the
padding on the title did was shift content within the title up to give
the impression of space between the title and other content.
- Adjusted the actual padding values to align with the iOS spec

Note: The screenshot diffs here are correct. By adding padding to the
toolbar we are increasing the height of the toolbar by 6px. As noted
above, we never truly had spacing between the large title and the
content since the text inside of the title was just being shifted by 6px
to give the impression of spacing.

Additionally, the padding values were further adjusted to match the iOS
spec:

| native | ionic | diff |
| - | - | - |
|
![native](https://github.com/ionic-team/ionic-framework/assets/2721089/10c51b1c-c52c-4871-add4-5af42cfda106)
|
![ionic](https://github.com/ionic-team/ionic-framework/assets/2721089/a1062dbf-4a3e-4022-97a1-dcae8b19725d)
|
![diff](https://github.com/ionic-team/ionic-framework/assets/2721089/c9506f5d-c21f-4d74-93c5-6d1a64ff4023)
|

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.4-dev.11691683954.1b6ed4bb`

---------

Co-authored-by: ionitron <hi@ionicframework.com>
2023-08-14 13:17:59 +00:00
Liam DeBeasi
84cf0f152f chore: remove old comment from playwright config (#27973)
Issue number: #

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Shawn noted that I had an outdated comment in the `playwright.config.ts`
file when working on
https://github.com/ionic-team/ionic-framework/pull/27961:
https://github.com/ionic-team/ionic-framework/pull/27961#pullrequestreview-1572374939
 
## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Remove the old comment

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-10 19:20:08 +00:00
Liam DeBeasi
28bd4ba720 fix(tap-click): do not error in document-less environment (#27972)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

While working on getting our starter app tests running on CI, I ran into
the following error:

```
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
ReferenceError: document is not defined
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
 ❯ Module.startTapClick node_modules/@ionic/core/components/index9.js:133:15
    131|   };
    132|   const doc = document;
    133|   doc.addEventListener('ionGestureCaptured', cancelActive);
       |               ^
    134|   doc.addEventListener('touchstart', onTouchStart, true);
    135|   doc.addEventListener('touchcancel', onTouchEnd, true);
 ❯ node_modules/@ionic/core/components/ion-app.js:21:113

This error originated in "src/App.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:
```

We are referencing `document` without any "document defined" checks.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Tap Click is only enabled if the `document` is available since we set
event listeners on the document.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-10 18:48:09 +00:00
Liam DeBeasi
b6f43e0e72 test(playwright): enable github reporter, test retries (#27961)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

The team would like to explore solutions for being informed of flaky
tests in a way that is not disruptive to our workflow. Currently, flaky
tests fail immediately which means we have to re-run them every time.
We'd like flaky tests to be automatically retried but also reported to
us so we can address them in a separate PR.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Enables the Playwright GitHub reporter. This will report about flaky
tests on the PR if applicable as well as in the CI results.
- Enables test retries. Tests will be retried up to 2 times before
failing.
- Disables reporting slow tests in the GitHub reporter. Some of our
tests require gesture interaction which are inherently slow but
otherwise working as intended. We don't necessarily need to know about
these right now.
- Disables "maxFailures". Tests that can fail at most once are never
detected as flaky since they are never retried. As a result, we need to
disable this in order to have flaky tests be reported to us.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-10 17:22:46 +00:00
Sean Perkins
87bc207dad chore(input): remove generated documentation for size attribute (#27951)
Issue number: Resolves #27945 

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

The `ion-input` accepts a `size` attribute that implies that it will
effect the size of the input under certain rules. This is not the case.
The `size` attribute has no effect on the size of the `input` element
since Ionic sets the input width to 100%.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Removes the documentation around the `size` attribute so that it will
be removed from the Ionic Docs
- Adds a task link to remove the `size` attribute in an upcoming major
release

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-10 15:33:57 +00:00
Brandy Carney
8c6dc29133 Merge release-7.2.3
Release 7.2.3
2023-08-09 13:35:00 -04:00
ionitron
3a263d14c3 chore(): update package lock files 2023-08-09 16:28:15 +00:00
ionitron
0cb37430d3 v7.2.3 2023-08-09 16:27:57 +00:00
Liam DeBeasi
e9fa30002b fix(button): hidden button is added when form is set async (#27955)
Issue number: resolves #27952

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

The hidden button in `ion-button` that is responsible for submitting the
form does not get added when the `form` property is set async.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- `ion-button` now checks to see if it needs to render a hidden button
whenever it re-renders. This allows it to account for changes to the
`type` property, `form` property, etc.

Since this code can potentially run multiple times I added an extra
check so we don't add multiple buttons to the form.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.3-dev.11691523847.1760ab58`
2023-08-09 14:35:11 +00:00
Amanda Johnston
07dee74714 refactor(datetime): remove unused isPresented variable (#27956)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

`ion-datetime` has a state variable `isPresented`, which is never set
and goes unused except to add a CSS class (also unused).

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

State variable and class removed.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-09 14:14:54 +00:00
Sean Perkins
aa326a6eda chore(react): update v18 test app to use vite (#27935)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

React 17/18 test apps use react-scripts. This does not align with our
starter templates.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Updates the React 18 test app to use Vite
- Leaves the React 17 test app on react-scripts for now
- Updates test app dependencies to align with the react starters

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-09 14:12:51 +00:00
Fabio Costa
1cf1eca002 fix(tab-button): update event type interface on React (#27950)
closes #27949

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

- Typescript is complaining about the `onClick` event type of the
`IonTabButton`

```ts
const App: React.FC = () => {
  async function handleTabClick(e: CustomEvent<HTMLIonTabButtonElement>) {
    alert(e.detail.tab);
  }

  return (
    <IonTabButton tab="myTab" onClick={handleTabClick}>
  );
};
```

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- `onClick` handler uses `CustomEvent` type
- Typescript does not error

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->




## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-09 14:05:39 +00:00
Liam DeBeasi
eb19c289d6 fix(datetime): changing months work if partially visible (#27917)
Issue number: resolves #27913

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

When determining what the changed month is, we grab the element at the
center of the datetime and then grab the nearest calendar month. This
works fine if the datetime is fully in view, but if the center point is
out of the viewport then this will return `null`. As a result, scrolling
in the datetime will break.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- We now check scroll position instead of querying for DOM elements at
coordinates. This allows the view to continue to update even if the
entire calendar body is outside the viewport.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.2-dev.11690996559.1019674a`
2023-08-04 18:41:25 +00:00
Liam DeBeasi
a0e6ac6013 fix(many): overlays present if isOpen is true on load (#27933)
Issue number: resolves #27928 

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Action sheet, alert, picker, and toast did not have logic where the
overlay presents if `isOpen="true"` on load. Modal, popover, and loading
had this logic but did not have test coverage.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Updated action sheet, alert, picker, and toast to present if
`isOpen="true"` on load
- Added test coverage to all overlays for this functionality.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.3-dev.11691156718.1638345c`
2023-08-04 17:00:21 +00:00
Liam DeBeasi
da55ab949e fix(modal): setCurrentBreakpoint respects animated prop (#27924)
Issue number: resolves #27923

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

`setCurrentBreakpoint` still animates even when `animated: false`.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- `setCurrentBreakpoint` jumps directly to the new breakpoint when
`animated: false`

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Updated design doc:
https://github.com/ionic-team/ionic-framework-design-documents/pull/137
Dev build: `7.2.3-dev.11691069391.1d91d2be`
2023-08-04 15:14:21 +00:00
Liam DeBeasi
a0b3ef02af fix(item-sliding): account for options added before watcher (#27915)
Issue number: resolves #27910

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

There is an edge case in our `ion-item-sliding` code where options can
be added after the `querySelectorAll` has been run in `updateOptions`
but before `watchForOptions` has been called which causes us to miss the
newly created options. These options can never be shown as a result.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- `watchForOptions` is called before the initial `updateOptions` call so
that we can re-run `updateOptions` in the event that options are added
while that first call is running.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.2-dev.11690983626.19a2a8cb`
2023-08-02 19:20:22 +00:00
Liam DeBeasi
9500769f11 fix(nav): improve reliability of swipe back gesture when quickly swiping back (#27904)
Issue number: resolves #27893

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

This is another instance of
https://github.com/ionic-team/ionic-framework/issues/22895. The
`progressCallback` function is fires asynchronously, so it's possible
for the gesture start and end callbacks to run before the animation is
ever set in `progressCallback`. When this happens, the animation gets
locked up.

I previously fixed this in
https://github.com/ionic-team/ionic-framework/pull/23527 for
`ion-router-outlet`, but I did not fix it for `ion-nav`.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- If the gesture has ended by the time `progressCallback` fires, reset
the animation to the beginning so it does not get locked up.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Dev build: `7.2.2-dev.11690896715.12338339`
2023-08-02 18:48:34 +00:00
Liam DeBeasi
5992c619ad merge release-7.2.2
Release 7.2.2
2023-08-02 13:09:29 -04:00
ionitron
01857dd315 chore(): update package lock files 2023-08-02 15:59:53 +00:00
ionitron
dbe6f390ef v7.2.2 2023-08-02 15:59:37 +00:00
Liam DeBeasi
0c117cfe7f fix(select): popover uses modern form syntax (#27818)
Issue number: resolves #27071, resolves #27786

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

`ion-select-popover` is using the legacy syntax for `ion-checkbox` and
`ion-radio`.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Migrated checkbox and radio to use the modern syntax
- Updated the visual rendering tests to also check the checked state. I
noticed during development that I accidentally broke the checked state,
so I added tests so we can't accidentally break it again.

A couple notes on other screenshot diffs:

- On iOS, the item border line now extends past the radio circle. This
is an intentional behavior and aligns with native iOS. Having the radio
in the "start" slot is typically only done when the content in the
default slot is another interactive element (like and input) and not a
text label.
- On MD, the control heights are smaller. When comparing with
https://material-components.github.io/material-components-web-catalog/#/component/select,
the new behavior seems to be correct. Both the spec and Ionic item
heights are 48px. Interestingly, the radios in `ion-select-popover` have
always been 48px tall, but the checkboxes were 54px. Now both the radios
and checkboxes are 48px.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

---------

Co-authored-by: amandaejohnston <amandaejohnston@users.noreply.github.com>
Co-authored-by: ionitron <hi@ionicframework.com>
2023-08-01 17:35:51 +00:00
Liam DeBeasi
f14c440d63 fix(input, textarea): input does not block floating label (#27870)
Issue number: resolves #27812

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

We currently have CSS to ensure the floating/stacked label is not
obscured by the input/textarea when using the outline styles. However,
it was discovered that this scenario can happen with any
floating/stacked label not just when the input/textarea is using the
outline style.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Floating/stacked labels appear on top of the input/textarea regardless
of fill mode.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->


Dev build: `7.2.1-dev.11690464203.1b2b4419`

---------

Co-authored-by: ionitron <hi@ionicframework.com>
2023-08-01 15:48:55 +00:00
Liam DeBeasi
bd1910ba69 fix(datetime-button): render correct text when passing partial date values (#27816)
Issue number: resolves #27797

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Datetime Button passes a parsed value to one of the many text formatting
utilities we have, such as `getMonthAndYear`. However, developers can
pass partial date values such as `2022` or `2022-04` (April 2022).
According to
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format,
these are still valid date strings.

However, the `parseDate` utility does not add fallback values. So
passing `2022` will cause the `day` and `month` fields to be
`undefined`. This means that `getNormalizedDate` passes `'//2022'` to
the `Date` constructor.

Some browsers, such as Chrome, will automatically account for the stray
slashes and still return a valid date. Other browsers, such as Safari,
do not do this and will either return "Invalid Date" or throw an error.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Date normalizing utility now has fallback values so we always pass in
a valid date. In the example above, `getNormalizedDate` will now pass
`'1/1/2022'` instead of `'//2022'` to the `Date` constructor.
- Refactored other utils that use `new Date` to make use of
`getNormalizedDate` since they are also impacted.

Note: I added an E2E test instead of a spec test because I want to test
cross-browser behavior to ensure consistency.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2023-08-01 15:44:05 +00:00
128 changed files with 7165 additions and 20306 deletions

View File

@@ -14,6 +14,6 @@ runs:
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
- name: Exract Archive
- name: Extract Archive
run: unzip -q -o ${{ inputs.path }}/${{ inputs.filename }}
shell: bash

View File

@@ -1,5 +1,8 @@
name: 'Test Core Spec'
description: 'Test Core Spec'
inputs:
stencil-version:
description: 'The NPM tag of @stencil/core to install.'
runs:
using: 'composite'
steps:
@@ -7,9 +10,14 @@ runs:
with:
node-version: 16.x
- name: Install Dependencies
run: npm install
run: npm ci
working-directory: ./core
shell: bash
- name: Install Stencil ${{ inputs.stencil-version }}
run: npm install @stencil/core@${{ inputs.stencil-version }}
shell: bash
working-directory: ./core
if: ${{ inputs.stencil-version != '' }}
- uses: ./.github/workflows/actions/download-archive
with:
name: ionic-core

View File

@@ -46,6 +46,8 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/actions/test-core-spec
with:
stencil-version: nightly
test-core-screenshot:
strategy:

View File

@@ -3,6 +3,51 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.2.4](https://github.com/ionic-team/ionic-framework/compare/v7.2.3...v7.2.4) (2023-08-16)
### Bug Fixes
* **tap-click:** do not error in document-less environment ([#27972](https://github.com/ionic-team/ionic-framework/issues/27972)) ([28bd4ba](https://github.com/ionic-team/ionic-framework/commit/28bd4ba720bb77d5f5c48cd7a45e0015daddc9dd))
* **title:** large title aligns with ios spec ([#27969](https://github.com/ionic-team/ionic-framework/issues/27969)) ([8fa12fc](https://github.com/ionic-team/ionic-framework/commit/8fa12fc88857df27a1ca11249f0085e100fe1474)), closes [#27966](https://github.com/ionic-team/ionic-framework/issues/27966)
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
### Bug Fixes
* **button:** hidden button is added when form is set async ([#27955](https://github.com/ionic-team/ionic-framework/issues/27955)) ([e9fa300](https://github.com/ionic-team/ionic-framework/commit/e9fa30002bd5dec4f2f56a15c84eec1b3e794942)), closes [#27952](https://github.com/ionic-team/ionic-framework/issues/27952)
* **datetime:** changing months work if partially visible ([#27917](https://github.com/ionic-team/ionic-framework/issues/27917)) ([eb19c28](https://github.com/ionic-team/ionic-framework/commit/eb19c289d6581639f6df7aff002bebdf2b27d31c)), closes [#27913](https://github.com/ionic-team/ionic-framework/issues/27913)
* **item-sliding:** account for options added before watcher ([#27915](https://github.com/ionic-team/ionic-framework/issues/27915)) ([a0b3ef0](https://github.com/ionic-team/ionic-framework/commit/a0b3ef02af718e232246515bb873ad8c090fa55d)), closes [#27910](https://github.com/ionic-team/ionic-framework/issues/27910)
* **many:** overlays present if isOpen is true on load ([#27933](https://github.com/ionic-team/ionic-framework/issues/27933)) ([a0e6ac6](https://github.com/ionic-team/ionic-framework/commit/a0e6ac6013552c5e3acdde33575d4aaf4d4c0bda)), closes [#27928](https://github.com/ionic-team/ionic-framework/issues/27928)
* **modal:** setCurrentBreakpoint respects animated prop ([#27924](https://github.com/ionic-team/ionic-framework/issues/27924)) ([da55ab9](https://github.com/ionic-team/ionic-framework/commit/da55ab949ef1894738da5a6241176089b7a2b6e3)), closes [#27923](https://github.com/ionic-team/ionic-framework/issues/27923)
* **nav:** improve reliability of swipe back gesture when quickly swiping back ([#27904](https://github.com/ionic-team/ionic-framework/issues/27904)) ([9500769](https://github.com/ionic-team/ionic-framework/commit/9500769f114d180613f0340b1a328b5e631b7188)), closes [#27893](https://github.com/ionic-team/ionic-framework/issues/27893)
* **tab-button:** update event type interface on React ([#27950](https://github.com/ionic-team/ionic-framework/issues/27950)) ([1cf1eca](https://github.com/ionic-team/ionic-framework/commit/1cf1eca00239f3e98854466116e42f9a2e7b4590)), closes [#27949](https://github.com/ionic-team/ionic-framework/issues/27949)
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
### Bug Fixes
* **datetime-button:** render correct text when passing partial date values ([#27816](https://github.com/ionic-team/ionic-framework/issues/27816)) ([bd1910b](https://github.com/ionic-team/ionic-framework/commit/bd1910ba69348877ad5f99d9db2b59d06693b91e)), closes [#27797](https://github.com/ionic-team/ionic-framework/issues/27797)
* **input, textarea:** input does not block floating label ([#27870](https://github.com/ionic-team/ionic-framework/issues/27870)) ([f14c440](https://github.com/ionic-team/ionic-framework/commit/f14c440d6321ef9f168b272338e5cd21cab384ef)), closes [#27812](https://github.com/ionic-team/ionic-framework/issues/27812)
* **item-options:** use correct safe area padding ([#27853](https://github.com/ionic-team/ionic-framework/issues/27853)) ([0b8f1bc](https://github.com/ionic-team/ionic-framework/commit/0b8f1bc7dd4170a2a8c9ed3aede173dd489b25ea))
* **radio:** radios can be focused and are announced with group ([#27817](https://github.com/ionic-team/ionic-framework/issues/27817)) ([ba2f49b](https://github.com/ionic-team/ionic-framework/commit/ba2f49b8a460520d20ac198db800ea2d9e5b015f)), closes [#27438](https://github.com/ionic-team/ionic-framework/issues/27438)
* **react, vue:** custom animations are used when going back ([#27895](https://github.com/ionic-team/ionic-framework/issues/27895)) ([824033f](https://github.com/ionic-team/ionic-framework/commit/824033f1d4b4a3e5d4c6a978a39e5bb1f33b5bb4)), closes [#27873](https://github.com/ionic-team/ionic-framework/issues/27873)
* **select:** popover uses modern form syntax ([#27818](https://github.com/ionic-team/ionic-framework/issues/27818)) ([0c117cf](https://github.com/ionic-team/ionic-framework/commit/0c117cfe7f383b7c7837d27de5a6eee12ddd6c2f)), closes [#27071](https://github.com/ionic-team/ionic-framework/issues/27071) [#27786](https://github.com/ionic-team/ionic-framework/issues/27786)
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)

View File

@@ -3,6 +3,49 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.2.4](https://github.com/ionic-team/ionic-framework/compare/v7.2.3...v7.2.4) (2023-08-16)
### Bug Fixes
* **tap-click:** do not error in document-less environment ([#27972](https://github.com/ionic-team/ionic-framework/issues/27972)) ([28bd4ba](https://github.com/ionic-team/ionic-framework/commit/28bd4ba720bb77d5f5c48cd7a45e0015daddc9dd))
* **title:** large title aligns with ios spec ([#27969](https://github.com/ionic-team/ionic-framework/issues/27969)) ([8fa12fc](https://github.com/ionic-team/ionic-framework/commit/8fa12fc88857df27a1ca11249f0085e100fe1474)), closes [#27966](https://github.com/ionic-team/ionic-framework/issues/27966)
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
### Bug Fixes
* **button:** hidden button is added when form is set async ([#27955](https://github.com/ionic-team/ionic-framework/issues/27955)) ([e9fa300](https://github.com/ionic-team/ionic-framework/commit/e9fa30002bd5dec4f2f56a15c84eec1b3e794942)), closes [#27952](https://github.com/ionic-team/ionic-framework/issues/27952)
* **datetime:** changing months work if partially visible ([#27917](https://github.com/ionic-team/ionic-framework/issues/27917)) ([eb19c28](https://github.com/ionic-team/ionic-framework/commit/eb19c289d6581639f6df7aff002bebdf2b27d31c)), closes [#27913](https://github.com/ionic-team/ionic-framework/issues/27913)
* **item-sliding:** account for options added before watcher ([#27915](https://github.com/ionic-team/ionic-framework/issues/27915)) ([a0b3ef0](https://github.com/ionic-team/ionic-framework/commit/a0b3ef02af718e232246515bb873ad8c090fa55d)), closes [#27910](https://github.com/ionic-team/ionic-framework/issues/27910)
* **many:** overlays present if isOpen is true on load ([#27933](https://github.com/ionic-team/ionic-framework/issues/27933)) ([a0e6ac6](https://github.com/ionic-team/ionic-framework/commit/a0e6ac6013552c5e3acdde33575d4aaf4d4c0bda)), closes [#27928](https://github.com/ionic-team/ionic-framework/issues/27928)
* **modal:** setCurrentBreakpoint respects animated prop ([#27924](https://github.com/ionic-team/ionic-framework/issues/27924)) ([da55ab9](https://github.com/ionic-team/ionic-framework/commit/da55ab949ef1894738da5a6241176089b7a2b6e3)), closes [#27923](https://github.com/ionic-team/ionic-framework/issues/27923)
* **nav:** improve reliability of swipe back gesture when quickly swiping back ([#27904](https://github.com/ionic-team/ionic-framework/issues/27904)) ([9500769](https://github.com/ionic-team/ionic-framework/commit/9500769f114d180613f0340b1a328b5e631b7188)), closes [#27893](https://github.com/ionic-team/ionic-framework/issues/27893)
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
### Bug Fixes
* **datetime-button:** render correct text when passing partial date values ([#27816](https://github.com/ionic-team/ionic-framework/issues/27816)) ([bd1910b](https://github.com/ionic-team/ionic-framework/commit/bd1910ba69348877ad5f99d9db2b59d06693b91e)), closes [#27797](https://github.com/ionic-team/ionic-framework/issues/27797)
* **input, textarea:** input does not block floating label ([#27870](https://github.com/ionic-team/ionic-framework/issues/27870)) ([f14c440](https://github.com/ionic-team/ionic-framework/commit/f14c440d6321ef9f168b272338e5cd21cab384ef)), closes [#27812](https://github.com/ionic-team/ionic-framework/issues/27812)
* **item-options:** use correct safe area padding ([#27853](https://github.com/ionic-team/ionic-framework/issues/27853)) ([0b8f1bc](https://github.com/ionic-team/ionic-framework/commit/0b8f1bc7dd4170a2a8c9ed3aede173dd489b25ea))
* **radio:** radios can be focused and are announced with group ([#27817](https://github.com/ionic-team/ionic-framework/issues/27817)) ([ba2f49b](https://github.com/ionic-team/ionic-framework/commit/ba2f49b8a460520d20ac198db800ea2d9e5b015f)), closes [#27438](https://github.com/ionic-team/ionic-framework/issues/27438)
* **select:** popover uses modern form syntax ([#27818](https://github.com/ionic-team/ionic-framework/issues/27818)) ([0c117cf](https://github.com/ionic-team/ionic-framework/commit/0c117cfe7f383b7c7837d27de5a6eee12ddd6c2f)), closes [#27071](https://github.com/ionic-team/ionic-framework/issues/27071) [#27786](https://github.com/ionic-team/ionic-framework/issues/27786)
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)

48
core/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@ionic/core",
"version": "7.2.1",
"version": "7.2.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/core",
"version": "7.2.1",
"version": "7.2.4",
"license": "MIT",
"dependencies": {
"@stencil/core": "^3.4.0",
@@ -15,14 +15,14 @@
},
"devDependencies": {
"@axe-core/playwright": "^4.7.3",
"@capacitor/core": "^5.2.2",
"@capacitor/core": "^5.2.3",
"@capacitor/haptics": "^5.0.6",
"@capacitor/keyboard": "^5.0.6",
"@capacitor/status-bar": "^5.0.6",
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
"@jest/core": "^27.5.1",
"@playwright/test": "^1.36.2",
"@playwright/test": "^1.37.0",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/angular-output-target": "^0.7.1",
@@ -607,9 +607,9 @@
"dev": true
},
"node_modules/@capacitor/core": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.2.tgz",
"integrity": "sha512-3jKECZC5+YD2rljMZm1e/K3AYyoxUmLDZCyofTPbRYPBSI0wJh5ZCkX+XIGzNM0o/Wokl3Voa1JB8xsLC0MPxA==",
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.3.tgz",
"integrity": "sha512-Q1zbgt3Mvldy7six2/GX54kTL0ozgnR37jeDUAXL/fOJBF4Iorr/8A0OjGEAnwEjpR1la7uFZUunESMFyMLhEQ==",
"dev": true,
"dependencies": {
"tslib": "^2.1.0"
@@ -1541,13 +1541,13 @@
}
},
"node_modules/@playwright/test": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.0.tgz",
"integrity": "sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.36.2"
"playwright-core": "1.37.0"
},
"bin": {
"playwright": "cli.js"
@@ -8194,9 +8194,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.0.tgz",
"integrity": "sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -10788,9 +10788,9 @@
"dev": true
},
"@capacitor/core": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.2.tgz",
"integrity": "sha512-3jKECZC5+YD2rljMZm1e/K3AYyoxUmLDZCyofTPbRYPBSI0wJh5ZCkX+XIGzNM0o/Wokl3Voa1JB8xsLC0MPxA==",
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.3.tgz",
"integrity": "sha512-Q1zbgt3Mvldy7six2/GX54kTL0ozgnR37jeDUAXL/fOJBF4Iorr/8A0OjGEAnwEjpR1la7uFZUunESMFyMLhEQ==",
"dev": true,
"requires": {
"tslib": "^2.1.0"
@@ -11455,14 +11455,14 @@
}
},
"@playwright/test": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.0.tgz",
"integrity": "sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==",
"dev": true,
"requires": {
"@types/node": "*",
"fsevents": "2.3.2",
"playwright-core": "1.36.2"
"playwright-core": "1.37.0"
}
},
"@rollup/plugin-node-resolve": {
@@ -16332,9 +16332,9 @@
}
},
"playwright-core": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.0.tgz",
"integrity": "sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==",
"dev": true
},
"postcss": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "7.2.1",
"version": "7.2.4",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -37,14 +37,14 @@
},
"devDependencies": {
"@axe-core/playwright": "^4.7.3",
"@capacitor/core": "^5.2.2",
"@capacitor/core": "^5.2.3",
"@capacitor/haptics": "^5.0.6",
"@capacitor/keyboard": "^5.0.6",
"@capacitor/status-bar": "^5.0.6",
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
"@jest/core": "^27.5.1",
"@playwright/test": "^1.36.2",
"@playwright/test": "^1.37.0",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/angular-output-target": "^0.7.1",

View File

@@ -62,14 +62,16 @@ const config: PlaywrightTestConfig = {
},
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Fail fast on CI */
maxFailures: process.env.CI ? 1 : 0,
/* Flaky test should be either addressed or disabled until we can address them */
retries: 0,
maxFailures: 0,
retries: 2,
reportSlowTests: null,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
reporter: [
['html'],
['github']
],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */

View File

@@ -1277,9 +1277,6 @@ export namespace Components {
* The shape of the input. If "round" it will have an increased border radius.
*/
"shape"?: 'round';
/**
* The initial size of the control. This value is in pixels unless the value of the type attribute is `"text"` or `"password"`, in which case it is an integer number of characters. This attribute applies only when the `type` attribute is set to `"text"`, `"search"`, `"tel"`, `"url"`, `"email"`, or `"password"`, otherwise it is ignored.
*/
"size"?: number;
/**
* If `true`, the element will have its spelling and grammar checked.
@@ -5339,9 +5336,6 @@ declare namespace LocalJSX {
* The shape of the input. If "round" it will have an increased border radius.
*/
"shape"?: 'round';
/**
* The initial size of the control. This value is in pixels unless the value of the type attribute is `"text"` or `"password"`, in which case it is an integer number of characters. This attribute applies only when the `type` attribute is set to `"text"`, `"search"`, `"tel"`, `"url"`, `"email"`, or `"password"`, otherwise it is ignored.
*/
"size"?: number;
/**
* If `true`, the element will have its spelling and grammar checked.

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -2,6 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Watch, Component, Element, Event, Host, Method, Prop, h, readTask } from '@stencil/core';
import type { Gesture } from '@utils/gesture';
import { createButtonActiveGesture } from '@utils/gesture/button-active';
import { raf } from '@utils/helpers';
import {
BACKDROP,
createDelegateController,
@@ -318,25 +319,32 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
componentDidLoad() {
/**
* Do not create gesture if:
* 1. A gesture already exists
* 2. App is running in MD mode
* 3. A wrapper ref does not exist
* Only create gesture if:
* 1. A gesture does not already exist
* 2. App is running in iOS mode
* 3. A wrapper ref exists
* 4. A group ref exists
*/
const { groupEl, wrapperEl } = this;
if (this.gesture || getIonMode(this) === 'md' || !wrapperEl || !groupEl) {
return;
if (!this.gesture && getIonMode(this) === 'ios' && wrapperEl && groupEl) {
readTask(() => {
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
if (!isScrollable) {
this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
refEl.classList.contains('action-sheet-button')
);
this.gesture.enable(true);
}
});
}
readTask(() => {
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
if (!isScrollable) {
this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
refEl.classList.contains('action-sheet-button')
);
this.gesture.enable(true);
}
});
/**
* If action sheet was rendered with isOpen="true"
* then we should open action sheet immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
}
render() {

View File

@@ -30,5 +30,10 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ config, title }) =>
await expect(actionSheet).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-action-sheet is-open="true"></ion-action-sheet>', config);
await expect(page.locator('ion-action-sheet')).toBeVisible();
});
});
});

View File

@@ -3,6 +3,7 @@ import { Component, Element, Event, Host, Listen, Method, Prop, Watch, forceUpda
import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config';
import type { Gesture } from '@utils/gesture';
import { createButtonActiveGesture } from '@utils/gesture/button-active';
import { raf } from '@utils/helpers';
import {
createDelegateController,
createTriggerController,
@@ -346,19 +347,25 @@ export class Alert implements ComponentInterface, OverlayInterface {
componentDidLoad() {
/**
* Do not create gesture if:
* 1. A gesture already exists
* 2. App is running in MD mode
* 3. A wrapper ref does not exist
* Only create gesture if:
* 1. A gesture does not already exist
* 2. App is running in iOS mode
* 3. A wrapper ref exists
*/
if (this.gesture || getIonMode(this) === 'md' || !this.wrapperEl) {
return;
if (!this.gesture && getIonMode(this) === 'ios' && this.wrapperEl) {
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl: HTMLElement) =>
refEl.classList.contains('alert-button')
);
this.gesture.enable(true);
}
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl: HTMLElement) =>
refEl.classList.contains('alert-button')
);
this.gesture.enable(true);
/**
* If alert was rendered with isOpen="true"
* then we should open alert immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
}
/**

View File

@@ -29,5 +29,10 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ config, title }) =>
await ionAlertDidDismiss.next();
await expect(alert).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-alert is-open="true"></ion-alert>', config);
await expect(page.locator('ion-alert')).toBeVisible();
});
});
});

View File

@@ -153,19 +153,27 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
*/
@Event() ionBlur!: EventEmitter<void>;
connectedCallback(): void {
// Allow form to be submitted through `ion-button`
if (this.type !== 'button' && hasShadowDom(this.el)) {
this.formEl = this.findForm();
if (this.formEl) {
// Create a hidden native button inside of the form
this.formButtonEl = document.createElement('button');
this.formButtonEl.type = this.type;
this.formButtonEl.style.display = 'none';
// Only submit if the button is not disabled.
this.formButtonEl.disabled = this.disabled;
this.formEl.appendChild(this.formButtonEl);
private renderHiddenButton() {
const formEl = (this.formEl = this.findForm());
if (formEl) {
const { formButtonEl } = this;
/**
* If the form already has a rendered form button
* then do not append a new one again.
*/
if (formButtonEl !== null && formEl.contains(formButtonEl)) {
return;
}
// Create a hidden native button inside of the form
const newFormButtonEl = (this.formButtonEl = document.createElement('button'));
newFormButtonEl.type = this.type;
newFormButtonEl.style.display = 'none';
// Only submit if the button is not disabled.
newFormButtonEl.disabled = this.disabled;
formEl.appendChild(newFormButtonEl);
}
}
@@ -314,6 +322,11 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
if (fill == null) {
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
}
{
type !== 'button' && this.renderHiddenButton();
}
return (
<Host
onClick={this.handleClick}

View File

@@ -130,6 +130,29 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
expect(submitEvent).not.toHaveReceivedEvent();
});
test('should submit the form by id when form is set async', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27952',
});
await page.setContent(
`
<form id="myForm"></form>
<ion-button type="submit">Submit</ion-button>
`,
config
);
const submitEvent = await page.spyOnEvent('submit');
const button = page.locator('ion-button');
await button.evaluate((el: HTMLIonButtonElement) => (el.form = 'myForm'));
await page.click('ion-button');
expect(submitEvent).toHaveReceivedEvent();
});
});
test.describe(title('should throw a warning if the form cannot be found'), () => {

View File

@@ -0,0 +1,31 @@
import { newSpecPage } from '@stencil/core/testing';
import { Button } from '../../button';
describe('Button: Hidden Form Button', () => {
it('should not add multiple buttons to the form', async () => {
const page = await newSpecPage({
components: [Button],
html: `
<form id="my-form"></form>
<ion-button form="my-form" type="submit">Submit</ion-button>
`,
});
const getButtons = () => {
return page.body.querySelectorAll('form button');
};
const form = page.body.querySelectorAll('form');
const button = page.body.querySelector('ion-button');
await page.waitForChanges();
expect(getButtons().length).toEqual(1);
// Re-render the component
button.color = 'danger';
await page.waitForChanges();
expect(getButtons().length).toEqual(1);
});
});

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -122,6 +122,42 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
await expect(dateTarget).toContainText('May 10, 2023');
});
test('should set only month and year when only passing month and year', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27797',
});
await page.setContent(
`
<ion-datetime-button locale="en-US" datetime="datetime"></ion-datetime-button>
<ion-datetime id="datetime" value="2022-01" presentation="month-year"></ion-datetime>
`,
config
);
await page.waitForSelector('.datetime-ready');
await expect(page.locator('#date-button')).toContainText('January 2022');
await expect(page.locator('#time-button')).toBeHidden();
});
test('should set only year when passing only year', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27797',
});
await page.setContent(
`
<ion-datetime-button locale="en-US" datetime="datetime"></ion-datetime-button>
<ion-datetime id="datetime" value="2022" presentation="year"></ion-datetime>
`,
config
);
await page.waitForSelector('.datetime-ready');
await expect(page.locator('#date-button')).toContainText('2022');
await expect(page.locator('#time-button')).toBeHidden();
});
});
test.describe(title('datetime-button: locale'), () => {

View File

@@ -138,7 +138,6 @@ export class Datetime implements ComponentInterface {
@Element() el!: HTMLIonDatetimeElement;
@State() isPresented = false;
@State() isTimePopoverOpen = false;
/**
@@ -883,21 +882,18 @@ export class Datetime implements ComponentInterface {
const getChangedMonth = (parts: DatetimeParts): DatetimeParts | undefined => {
const box = calendarBodyRef.getBoundingClientRect();
const root = this.el!.shadowRoot!;
/**
* Get the element that is in the center of the calendar body.
* This will be an element inside of the active month.
* If the current scroll position is all the way to the left
* then we have scrolled to the previous month.
* Otherwise, assume that we have scrolled to the next
* month. We have a tolerance of 2px to account for
* sub pixel rendering.
*
* Check below the next line ensures that we did not
* swipe and abort (i.e. we swiped but we are still on the current month).
*/
const elementAtCenter = root.elementFromPoint(box.x + box.width / 2, box.y + box.height / 2);
/**
* If there is no element then the
* component may be re-rendering on a slow device.
*/
if (!elementAtCenter) return;
const month = elementAtCenter.closest('.calendar-month');
if (!month) return;
const month = calendarBodyRef.scrollLeft <= 2 ? startMonth : endMonth;
/**
* The edge of the month must be lined up with
@@ -2364,19 +2360,7 @@ export class Datetime implements ComponentInterface {
}
render() {
const {
name,
value,
disabled,
el,
color,
isPresented,
readonly,
showMonthAndYear,
preferWheel,
presentation,
size,
} = this;
const { name, value, disabled, el, color, readonly, showMonthAndYear, preferWheel, presentation, size } = this;
const mode = getIonMode(this);
const isMonthAndYearPresentation =
presentation === 'year' || presentation === 'month' || presentation === 'month-year';
@@ -2396,7 +2380,6 @@ export class Datetime implements ComponentInterface {
class={{
...createColorClasses(color, {
[mode]: true,
['datetime-presented']: isPresented,
['datetime-readonly']: readonly,
['datetime-disabled']: disabled,
'show-month-and-year': shouldShowMonthAndYear,

View File

@@ -301,21 +301,20 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
<ion-datetime
min="2022-01-15"
value="2022-02-01"
presentation="date"
presentation="month-year"
></ion-datetime>
`,
config
);
const datetime = page.locator('ion-datetime');
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
const ionChange = await page.spyOnEvent('ionChange');
await monthYearToggle.click();
await page.waitForChanges();
await page.waitForSelector('.datetime-ready');
await monthColumnItems.nth(0).click(); // switch to January
await page.waitForChanges();
await ionChange.next();
await expect(datetime).toHaveJSProperty('value', '2022-01-15T00:00:00');
});

View File

@@ -34,13 +34,14 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
`,
config
);
await page.waitForSelector('.datetime-ready');
const datetime = page.locator('ion-datetime');
const activeDayButton = page.locator('.calendar-day-active');
const monthYearButton = page.locator('.calendar-month-year');
const monthColumn = page.locator('.month-column');
const yearColumn = page.locator('.year-column');
const ionChange = await page.spyOnEvent('ionChange');
await datetime.evaluate((el: HTMLIonDatetimeElement) => (el.value = '2021-10-05'));
@@ -49,11 +50,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await page.waitForChanges();
// Select October 2021
// The year will automatically switch to 2021 when selecting 10
await monthColumn.locator('.picker-item[data-value="10"]').click();
await page.waitForChanges();
await yearColumn.locator('.picker-item[data-value="2021"]').click();
await page.waitForChanges();
await ionChange.next();
// Close month/year picker
await monthYearButton.click();

View File

@@ -113,7 +113,7 @@ export const generateDayAriaLabel = (locale: string, today: boolean, refParts: D
/**
* MM/DD/YYYY will return midnight in the user's timezone.
*/
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
const date = getNormalizedDate(refParts);
const labelString = new Intl.DateTimeFormat(locale, {
weekday: 'long',
@@ -134,7 +134,7 @@ export const generateDayAriaLabel = (locale: string, today: boolean, refParts: D
* Used for the header in MD mode.
*/
export const getMonthAndDay = (locale: string, refParts: DatetimeParts) => {
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
const date = getNormalizedDate(refParts);
return new Intl.DateTimeFormat(locale, { weekday: 'short', month: 'short', day: 'numeric', timeZone: 'UTC' }).format(
date
);
@@ -147,7 +147,7 @@ export const getMonthAndDay = (locale: string, refParts: DatetimeParts) => {
* Example: May 2021
*/
export const getMonthAndYear = (locale: string, refParts: DatetimeParts) => {
const date = new Date(`${refParts.month}/${refParts.day}/${refParts.year} GMT+0000`);
const date = getNormalizedDate(refParts);
return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric', timeZone: 'UTC' }).format(date);
};
@@ -183,11 +183,25 @@ export const getYear = (locale: string, refParts: DatetimeParts) => {
return getLocalizedDateTime(locale, refParts, { year: 'numeric' });
};
const getNormalizedDate = (refParts: DatetimeParts) => {
/**
* Given reference parts, return a JS Date object
* with a normalized time.
*/
export const getNormalizedDate = (refParts: DatetimeParts) => {
const timeString =
refParts.hour !== undefined && refParts.minute !== undefined ? ` ${refParts.hour}:${refParts.minute}` : '';
return new Date(`${refParts.month}/${refParts.day}/${refParts.year}${timeString} GMT+0000`);
/**
* We use / notation here for the date
* so we do not need to do extra work and pad values with zeroes.
* Values such as YYYY-MM are still valid, so
* we add fallback values so we still get
* a valid date otherwise we will pass in a string
* like "//2023". Some browsers, such as Chrome, will
* account for this and still return a valid date. However,
* this is not a consistent behavior across all browsers.
*/
return new Date(`${refParts.month ?? 1}/${refParts.day ?? 1}/${refParts.year ?? 2023}${timeString} GMT+0000`);
};
/**

View File

@@ -51,7 +51,7 @@
}
.header-collapse-condense ion-toolbar:first-of-type {
padding-top: 7px;
padding-top: 1px;
z-index: 1;
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -82,8 +82,6 @@
:host(.input-fill-outline) .label-text-wrapper,
:host(.input-fill-outline) .label-text-wrapper {
position: relative;
z-index: 1;
}
/**

View File

@@ -581,6 +581,13 @@
@include transform-origin(start, top);
max-width: 100%;
/**
* The 2 ensures the label
* remains on top of any browser
* autofill background too.
*/
z-index: 2;
}
/**

View File

@@ -268,9 +268,7 @@ export class Input implements ComponentInterface {
*/
@Prop() step?: string;
/**
* The initial size of the control. This value is in pixels unless the value of the type attribute is `"text"` or `"password"`, in which case it is an integer number of characters. This attribute applies only when the `type` attribute is set to `"text"`, `"search"`, `"tel"`, `"url"`, `"email"`, or `"password"`, otherwise it is ignored.
*/
// FW-4914 Remove this property in Ionic 8
@Prop() size?: number;
/**

View File

@@ -186,9 +186,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-slot-truncate`));
});
});
});
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('input: async label'), () => {
test('input should re-render when label slot is added async', async ({ page }) => {
await page.setContent(
@@ -213,4 +210,27 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-async-label`));
});
});
test.describe(title('input: floating/stacked label layering'), () => {
test('label should not be covered by text field', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27812',
});
await page.setContent(
`
<style>
.custom-input .native-wrapper {
background: pink;
}
</style>
<ion-input class="custom-input" label="My Label" label-placement="stacked"></ion-input>
`,
config
);
const input = page.locator('ion-input');
expect(await input.screenshot()).toMatchSnapshot(screenshot(`input-label-layering`));
});
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -76,12 +76,19 @@ export class ItemSliding implements ComponentInterface {
this.item = el.querySelector('ion-item');
this.contentEl = findClosestIonContent(el);
await this.updateOptions();
/**
* The MutationObserver needs to be added before we
* call updateOptions below otherwise we may miss
* ion-item-option elements that are added to the DOM
* while updateOptions is running and before the MutationObserver
* has been initialized.
*/
this.mutationObserver = watchForOptions<HTMLIonItemOptionElement>(el, 'ion-item-option', async () => {
await this.updateOptions();
});
await this.updateOptions();
this.gesture = (await import('../../utils/gesture')).createGesture({
el,
gestureName: 'item-swipe',

View File

@@ -3,7 +3,6 @@ import { configs, dragElementBy, test } from '@utils/test/playwright';
import { testSlidingItem } from '../test.utils';
// TODO FW-3006
/**
* item-sliding doesn't have mode-specific styling
*/
@@ -18,19 +17,12 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
});
});
// TODO FW-3006
/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('item-sliding: basic'), () => {
// mouse gesture is flaky on CI, skip for now
test.fixme('should open when swiped', async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
test('should open when swiped', async ({ page }) => {
await page.goto(`/src/components/item-sliding/test/basic`, config);
const item = page.locator('#item2');
@@ -41,7 +33,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
await expect(item).toHaveScreenshot(screenshot(`item-sliding-gesture`));
});
test.skip('should not scroll when the item-sliding is swiped', async ({ page, skip }) => {
test('should not scroll when the item-sliding is swiped', async ({ page, skip }) => {
skip.browser('webkit', 'mouse.wheel is not available in WebKit');
await page.goto(`/src/components/item-sliding/test/basic`, config);

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -2,6 +2,7 @@
// Item
// --------------------------------------------------
// TODO: FW-4955
:host {
/**
@@ -45,10 +46,10 @@
*
* @prop --ripple-color: Color of the item ripple effect
*
* @prop --highlight-height: The height of the highlight on the item
* @prop --highlight-color-focused: The color of the highlight on the item when focused
* @prop --highlight-color-valid: The color of the highlight on the item when valid
* @prop --highlight-color-invalid: The color of the highlight on the item when invalid
* @prop --highlight-height: The height of the highlight on the item. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
* @prop --highlight-color-focused: The color of the highlight on the item when focused. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
* @prop --highlight-color-valid: The color of the highlight on the item when valid. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
* @prop --highlight-color-invalid: The color of the highlight on the item when invalid. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
*/
--border-radius: 0px;
--border-width: 0px;

View File

@@ -23,5 +23,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionLoadingDidDismiss.next();
await expect(loading).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-loading is-open="true"></ion-loading>', config);
await expect(page.locator('ion-loading')).toBeVisible();
});
});
});

View File

@@ -31,6 +31,12 @@ export interface MoveSheetToBreakpointOptions {
* `true` if the sheet can be transitioned and dismissed off the view.
*/
canDismiss?: boolean;
/**
* If `true`, the sheet will animate to the breakpoint.
* If `false`, the sheet will jump directly to the breakpoint.
*/
animated: boolean;
}
export const createSheetGesture = (
@@ -246,11 +252,17 @@ export const createSheetGesture = (
breakpoint: closest,
breakpointOffset: offset,
canDismiss: canDismissBlocksGesture,
/**
* The swipe is user-driven, so we should
* always animate when the gesture ends.
*/
animated: true,
});
};
const moveSheetToBreakpoint = (options: MoveSheetToBreakpointOptions) => {
const { breakpoint, canDismiss, breakpointOffset } = options;
const { breakpoint, canDismiss, breakpointOffset, animated } = options;
/**
* canDismiss should only prevent snapping
* when users are trying to dismiss. If canDismiss
@@ -360,7 +372,7 @@ export const createSheetGesture = (
},
{ oneTimeCallback: true }
)
.progressEnd(1, 0, 500);
.progressEnd(1, 0, animated ? 500 : 0);
});
};

View File

@@ -761,7 +761,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
return;
}
const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints } = this;
const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints, animated } = this;
if (currentBreakpoint === breakpoint) {
return;
@@ -772,6 +772,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
breakpoint,
breakpointOffset: 1 - currentBreakpoint!,
canDismiss: canDismiss !== undefined && canDismiss !== true && breakpoints![0] === 0,
animated,
});
await this.sheetTransition;
this.sheetTransition = undefined;

View File

@@ -73,7 +73,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionModalDidPresent.next();
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, -500);
await dragElementBy(modalHeader, page, 0, 30);
const modal = page.locator('ion-modal');
expect(modal).not.toBe(null);

View File

@@ -9,12 +9,7 @@ import { CardModalPage } from '../fixtures';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('card modal - nav'), () => {
let cardModalPage: CardModalPage;
test.beforeEach(async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
test.beforeEach(async ({ page }) => {
cardModalPage = new CardModalPage(page);
await cardModalPage.navigate('/src/components/modal/test/card-nav?ionic:_testing=false', config);
});
@@ -33,7 +28,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const content = page.locator('.page-two-content');
await dragElementBy(content, page, 1000, 0, 10);
await dragElementBy(content, page, 370, 0, 10);
await ionNavDidChange.next();
});
@@ -47,7 +42,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionNavDidChange.next();
await cardModalPage.swipeToCloseModal('ion-modal ion-content.page-two-content');
await cardModalPage.swipeToCloseModal('ion-modal ion-content.page-two-content', true, 270);
});
});
});

View File

@@ -15,7 +15,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const modal = page.locator('ion-modal');
const content = (await page.$('ion-modal ion-content'))!;
await dragElementBy(content, page, 0, 500);
await dragElementBy(content, page, 0, 300);
await content.waitForElementState('stable');

View File

@@ -30,7 +30,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await content.evaluate((el: HTMLElement) => (el.scrollTop = 500));
await dragElementBy(content, page, 0, 500);
await dragElementBy(content, page, 0, 300);
await content.waitForElementState('stable');

View File

@@ -61,12 +61,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
test('it should not swipe to close when swiped on the content but the content is scrolled', async ({ page }) => {
const modal = await cardModalPage.openModalByTrigger('#card');
const content = (await page.$('ion-modal ion-content'))!;
const content = page.locator('ion-modal ion-content');
await content.evaluate((el: HTMLIonContentElement) => el.scrollToBottom(0));
await cardModalPage.swipeToCloseModal('ion-modal ion-content', false);
await content.waitForElementState('stable');
await content.waitFor();
await expect(modal).toBeVisible();
});
test('it should not swipe to close when swiped on the content but the content is scrolled even when content is replaced', async ({
@@ -76,12 +76,12 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await page.click('ion-button.replace');
const content = (await page.$('ion-modal ion-content'))!;
const content = page.locator('ion-modal ion-content');
await content.evaluate((el: HTMLIonContentElement) => el.scrollToBottom(0));
await cardModalPage.swipeToCloseModal('ion-modal ion-content', false);
await content.waitForElementState('stable');
await content.waitFor();
await expect(modal).toBeVisible();
});
test('content should be scrollable after gesture ends', async ({ page }) => {

View File

@@ -16,7 +16,7 @@ export class CardModalPage {
this.ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
}
async openModalByTrigger(selector: string) {
await this.page.click(selector);
await this.page.locator(selector).click();
await this.ionModalDidPresent.next();
return this.page.locator('ion-modal');

View File

@@ -20,5 +20,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionModalDidDismiss.next();
await expect(modal).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-modal is-open="true"></ion-modal>', config);
await expect(page.locator('ion-modal')).toBeVisible();
});
});
});

View File

@@ -129,7 +129,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const ionBreakpointDidChange = await page.spyOnEvent('ionBreakpointDidChange');
const header = page.locator('.modal-sheet ion-header');
await dragElementBy(header, page, 0, 150);
await dragElementBy(header, page, 0, 125);
await ionBreakpointDidChange.next();

View File

@@ -31,7 +31,7 @@ import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToVie
export class Nav implements NavOutlet {
private transInstr: TransitionInstruction[] = [];
private sbAni?: Animation;
private animationEnabled = true;
private gestureOrAnimationInProgress = false;
private useRouter = false;
private isTransitioning = false;
private destroyed = false;
@@ -869,7 +869,36 @@ export class Nav implements NavOutlet {
// or if it is a portal (modal, actionsheet, etc.)
const opts = ti.opts!;
const progressCallback = opts.progressAnimation ? (ani: Animation | undefined) => (this.sbAni = ani) : undefined;
const progressCallback = opts.progressAnimation
? (ani: Animation | undefined) => {
/**
* Because this progress callback is called asynchronously
* it is possible for the gesture to start and end before
* the animation is ever set. In that scenario, we should
* immediately call progressEnd so that the transition promise
* resolves and the gesture does not get locked up.
*/
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
this.gestureOrAnimationInProgress = true;
ani.onFinish(
() => {
this.gestureOrAnimationInProgress = false;
},
{ oneTimeCallback: true }
);
/**
* Playing animation to beginning
* with a duration of 0 prevents
* any flickering when the animation
* is later cleaned up.
*/
ani.progressEnd(0, 0, 0);
} else {
this.sbAni = ani;
}
}
: undefined;
const mode = getIonMode(this);
const enteringEl = enteringView.element!;
const leavingEl = leavingView && leavingView.element!;
@@ -1008,15 +1037,16 @@ export class Nav implements NavOutlet {
private canStart(): boolean {
return (
!this.gestureOrAnimationInProgress &&
!!this.swipeGesture &&
!this.isTransitioning &&
this.transInstr.length === 0 &&
this.animationEnabled &&
this.canGoBackSync()
);
}
private onStart() {
this.gestureOrAnimationInProgress = true;
this.pop({ direction: 'back', progressAnimation: true });
}
@@ -1028,10 +1058,9 @@ export class Nav implements NavOutlet {
private onEnd(shouldComplete: boolean, stepValue: number, dur: number) {
if (this.sbAni) {
this.animationEnabled = false;
this.sbAni.onFinish(
() => {
this.animationEnabled = true;
this.gestureOrAnimationInProgress = false;
},
{ oneTimeCallback: true }
);
@@ -1055,6 +1084,8 @@ export class Nav implements NavOutlet {
}
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
} else {
this.gestureOrAnimationInProgress = false;
}
}

View File

@@ -1,5 +1,6 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { raf } from '@utils/helpers';
import {
createDelegateController,
createTriggerController,
@@ -199,6 +200,16 @@ export class Picker implements ComponentInterface, OverlayInterface {
setOverlayId(this.el);
}
componentDidLoad() {
/**
* If picker was rendered with isOpen="true"
* then we should open picker immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
}
/**
* Present the picker overlay after it has been created.
*/

View File

@@ -23,5 +23,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionPickerDidDismiss.next();
await expect(picker).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-picker is-open="true"></ion-picker>', config);
await expect(page.locator('ion-picker')).toBeVisible();
});
});
});

View File

@@ -0,0 +1,11 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('popover: isOpen'), () => {
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-popover is-open="true"></ion-popover>', config);
await expect(page.locator('ion-popover')).toBeVisible();
});
});
});

View File

@@ -77,13 +77,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
expect(await scrollEl.evaluate((el: HTMLElement) => el.scrollTop)).toEqual(0);
const box = (await knobEl.boundingBox())!;
const centerX = box.x + box.width / 2;
const centerY = box.y + box.height / 2;
await page.mouse.move(centerX, centerY);
await page.mouse.down();
await page.mouse.move(centerX + 30, centerY);
await dragElementBy(knobEl, page, 30, 0, undefined, undefined, false);
/**
* Do not use scrollToBottom() or other scrolling methods

View File

@@ -10,15 +10,28 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
/**
* The mouse events are flaky on CI
*/
test.fixme('should emit start/end events', async ({ page }, testInfo) => {
await page.setContent(`<ion-range value="20"></ion-range>`, config);
test.fixme('should emit start/end events', async ({ page }) => {
/**
* Requires padding to prevent the knob from being clipped.
* If it's clipped, then the value might be one off.
* For example, if the knob is clipped on the right, then the value
* will be 99 instead of 100.
*/
await page.setContent(
`
<div style="padding: 0 20px">
<ion-range value="20"></ion-range>
</div>
`,
config
);
const rangeStart = await page.spyOnEvent('ionKnobMoveStart');
const rangeEnd = await page.spyOnEvent('ionKnobMoveEnd');
const rangeEl = page.locator('ion-range');
await dragElementBy(rangeEl, page, testInfo.project.metadata.rtl ? -300 : 300, 0);
await dragElementBy(rangeEl, page, 300, 0);
await page.waitForChanges();
/**
@@ -65,13 +78,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
expect(await scrollEl.evaluate((el: HTMLElement) => el.scrollTop)).toEqual(0);
const box = (await knobEl.boundingBox())!;
const centerX = box.x + box.width / 2;
const centerY = box.y + box.height / 2;
await page.mouse.move(centerX, centerY);
await page.mouse.down();
await page.mouse.move(centerX + 30, centerY);
await dragElementBy(knobEl, page, 30, 0, undefined, undefined, false);
/**
* Do not use scrollToBottom() or other scrolling methods
@@ -118,13 +125,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const rangeHandle = page.locator('ion-range .range-knob-handle');
const ionChangeSpy = await page.spyOnEvent('ionChange');
const boundingBox = await rangeHandle.boundingBox();
await rangeHandle.hover();
await page.mouse.down();
await page.mouse.move(boundingBox!.x + 100, boundingBox!.y);
await page.mouse.up();
await dragElementBy(rangeHandle, page, 100, 0);
await ionChangeSpy.next();
@@ -169,11 +170,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const rangeHandle = page.locator('ion-range .range-knob-handle');
const ionInputSpy = await page.spyOnEvent('ionInput');
const boundingBox = await rangeHandle.boundingBox();
await rangeHandle.hover();
await page.mouse.down();
await page.mouse.move(boundingBox!.x + 100, boundingBox!.y);
await dragElementBy(rangeHandle, page, 100, 0, undefined, undefined, false);
await ionInputSpy.next();

View File

@@ -3,13 +3,11 @@ import { configs, test } from '@utils/test/playwright';
import { pullToRefresh } from '../test.utils';
// TODO FW-2795: Enable this test when touch events/gestures are better supported in Playwright
/**
* This behavior does not vary across directions.
*/
configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe.skip(title('refresher: basic'), () => {
test.describe(title('refresher: basic'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/refresher/test/basic', config);
});

View File

@@ -3,12 +3,11 @@ import { configs, test } from '@utils/test/playwright';
import { pullToRefresh } from '../test.utils';
// TODO FW-2795: Enable this test when touch events/gestures are better supported in Playwright
/**
* This behavior does not vary across directions.
*/
configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe.skip(title('refresher: custom scroll target'), () => {
test.describe(title('refresher: custom scroll target'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/refresher/test/scroll-target', config);
});
@@ -19,7 +18,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
expect(await items.count()).toBe(30);
await pullToRefresh(page, '#inner-scroll');
await pullToRefresh(page);
expect(await items.count()).toBe(60);
});
@@ -39,7 +38,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
expect(await items.count()).toBe(30);
await pullToRefresh(page, '#inner-scroll');
await pullToRefresh(page);
expect(await items.count()).toBe(60);
});

View File

@@ -18,7 +18,7 @@ const pullToRefresh = async (page: E2EPage, selector = 'body') => {
const ev = await page.spyOnEvent('ionRefreshComplete');
await dragElementByYAxis(target, page, 400);
await dragElementByYAxis(target, page, 320);
await ev.next();
};

View File

@@ -1,18 +1,12 @@
import { expect } from '@playwright/test';
import { configs, test, dragElementBy } from '@utils/test/playwright';
// TODO FW-3079
/**
* Reorder group does not have per-mode styles
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe.skip(title('reorder group: interactive'), () => {
test.beforeEach(async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
test.describe(title('reorder group: interactive'), () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/reorder-group/test/interactive`, config);
});
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {

View File

@@ -1,17 +1,12 @@
import { expect } from '@playwright/test';
import { configs, test, dragElementBy } from '@utils/test/playwright';
// TODO FW-3079
/**
* Reorder group does not have per-mode styles
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe.skip(title('reorder group: nested'), () => {
test.beforeEach(async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
test.describe(title('reorder group: nested'), () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/reorder-group/test/nested`, config);
});
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {

View File

@@ -1,17 +1,12 @@
import { expect } from '@playwright/test';
import { configs, test, dragElementBy } from '@utils/test/playwright';
// TODO FW-3079
/**
* Reorder group does not have per-mode styles
*/
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe.skip(title('reorder group: scroll-target'), () => {
test.beforeEach(async ({ page, skip }) => {
skip.browser(
(browserName: string) => browserName !== 'chromium',
'dragElementBy is flaky outside of Chrome browsers.'
);
test.describe(title('reorder group: scroll-target'), () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/reorder-group/test/scroll-target`, config);
});
test('should drag and drop when ion-reorder wraps ion-item', async ({ page }) => {

View File

@@ -1,7 +1,7 @@
@import "./select-popover";
@import "./select-popover.md.vars";
ion-list ion-radio {
ion-list ion-radio::part(container) {
opacity: 0;
}

View File

@@ -1,5 +1,5 @@
import type { ComponentInterface } from '@stencil/core';
import { Element, Component, Host, Prop, h } from '@stencil/core';
import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core';
import { safeCall } from '@utils/overlays';
import { getClassMap } from '@utils/theme';
@@ -116,19 +116,28 @@ export class SelectPopover implements ComponentInterface {
renderCheckboxOptions(options: SelectPopoverOption[]) {
return options.map((option) => (
<ion-item class={getClassMap(option.cssClass)}>
<ion-item
class={{
// TODO FW-4784
'item-checkbox-checked': option.checked,
...getClassMap(option.cssClass),
}}
>
<ion-checkbox
slot="start"
value={option.value}
disabled={option.disabled}
checked={option.checked}
legacy={true}
justify="start"
labelPlacement="end"
onIonChange={(ev) => {
this.setChecked(ev);
this.callOptionHandler(ev);
// TODO FW-4784
forceUpdate(this);
}}
></ion-checkbox>
<ion-label>{option.text}</ion-label>
>
{option.text}
</ion-checkbox>
</ion-item>
));
}
@@ -139,12 +148,16 @@ export class SelectPopover implements ComponentInterface {
return (
<ion-radio-group value={checked} onIonChange={(ev) => this.callOptionHandler(ev)}>
{options.map((option) => (
<ion-item class={getClassMap(option.cssClass)}>
<ion-label>{option.text}</ion-label>
<ion-item
class={{
// TODO FW-4784
'item-radio-checked': option.value === checked,
...getClassMap(option.cssClass),
}}
>
<ion-radio
value={option.value}
disabled={option.disabled}
legacy={true}
onClick={() => this.dismissParentPopover()}
onKeyUp={(ev) => {
if (ev.key === ' ') {
@@ -156,7 +169,9 @@ export class SelectPopover implements ComponentInterface {
this.dismissParentPopover();
}
}}
></ion-radio>
>
{option.text}
</ion-radio>
</ion-item>
))}
</ion-radio-group>

View File

@@ -81,11 +81,11 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
selectPopoverPage = new SelectPopoverPage(page);
});
test('should not have visual regressions with single selection', async () => {
await selectPopoverPage.setup(config, options, false);
await selectPopoverPage.setup(config, checkedOptions, false);
await selectPopoverPage.screenshot(screenshot, 'select-popover-diff');
});
test('should not have visual regressions with multiple selection', async () => {
await selectPopoverPage.setup(config, options, true);
await selectPopoverPage.setup(config, checkedOptions, true);
await selectPopoverPage.screenshot(screenshot, 'select-popover-multiple-diff');
});
});

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -302,4 +302,27 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
await expect(page.locator('.container')).toHaveScreenshot(screenshot(`textarea-multi-line-sizing`));
});
});
test.describe(title('textarea: floating/stacked label layering'), () => {
test('label should not be covered by text field', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/27812',
});
await page.setContent(
`
<style>
.custom-textarea .native-wrapper {
background: pink;
}
</style>
<ion-textarea class="custom-textarea" label="My Label" label-placement="stacked"></ion-textarea>
`,
config
);
const textarea = page.locator('ion-textarea');
expect(await textarea.screenshot()).toMatchSnapshot(screenshot(`textarea-label-layering`));
});
});
});

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -82,8 +82,6 @@
:host(.textarea-fill-outline) .label-text-wrapper,
:host(.textarea-fill-outline) .label-text-wrapper {
position: relative;
z-index: 1;
}
/**

View File

@@ -629,6 +629,13 @@
@include padding(0px);
max-width: 100%;
/**
* The 2 ensures the label
* remains on top of any browser
* autofill background too.
*/
z-index: 2;
}
/**

View File

@@ -12,3 +12,23 @@ configs().forEach(({ title, screenshot, config }) => {
});
});
});
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('title: special characters'), () => {
test('should not cut off characters', async ({ page }) => {
await page.setContent(
`
<ion-header>
<ion-toolbar>
<ion-title size="large">ÔÔÔ</ion-title>
</ion-toolbar>
</ion-header>
`,
config
);
const title = page.locator('ion-title');
await expect(title).toHaveScreenshot(screenshot('title-characters'));
});
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -49,8 +49,6 @@
min-width: 100%;
padding-bottom: 6px;
font-size: 34px;
font-weight: 700;

View File

@@ -24,5 +24,10 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionToastDidDismiss.next();
await expect(toast).toBeHidden();
});
test('should open if isOpen is true on load', async ({ page }) => {
await page.setContent('<ion-toast is-open="true"></ion-toast>', config);
await expect(page.locator('ion-toast')).toBeVisible();
});
});
});

View File

@@ -1,6 +1,7 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { State, Watch, Component, Element, Event, h, Host, Method, Prop } from '@stencil/core';
import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config';
import { raf } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import {
createDelegateController,
@@ -253,6 +254,16 @@ export class Toast implements ComponentInterface, OverlayInterface {
setOverlayId(this.el);
}
componentDidLoad() {
/**
* If toast was rendered with isOpen="true"
* then we should open toast immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
}
/**
* Present the toast overlay after it has been created.
*/

View File

@@ -84,6 +84,16 @@
// Toolbar: Large Title
// --------------------------------------------------
/**
* Ensure there is enough spacing between the large
* title and any potential content in subsequent
* toolbars. We do not add padding to the title
* itself because it is absolutely positioned.
*/
:host(.toolbar-title-large) {
padding-bottom: 7px;
}
:host(.toolbar-title-large) .toolbar-container {
flex-wrap: wrap;
align-items: flex-start;
@@ -94,4 +104,4 @@
order: map-get($toolbar-order-ios, title-large);
min-width: 100%;
}
}

View File

@@ -1,7 +1,13 @@
import { doc } from '@utils/browser';
import type { Config } from '../../interface';
import { now, pointerCoord } from '../helpers';
export const startTapClick = (config: Config) => {
if (doc === undefined) {
return;
}
let lastTouch = -MOUSE_WAIT * 10;
let lastActivated = 0;
@@ -143,7 +149,6 @@ export const startTapClick = (config: Config) => {
}
};
const doc = document;
doc.addEventListener('ionGestureCaptured', cancelActive);
doc.addEventListener('touchstart', onTouchStart, true);

View File

@@ -1,3 +1,11 @@
/**
* The drag gesture will not operate as expected when the element is dragged outside of the viewport because the Mouse class does not fire events outside of the viewport.
*
* For example, if the mouse is moved outside of the viewport, then the `mouseup` event will not fire.
*
* See https://playwright.dev/docs/api/class-mouse#mouse-move for more information.
*/
import type { ElementHandle, Locator } from '@playwright/test';
import type { E2EPage } from './';
@@ -8,7 +16,8 @@ export const dragElementBy = async (
dragByX = 0,
dragByY = 0,
startXCoord?: number,
startYCoord?: number
startYCoord?: number,
releaseDrag = true
) => {
const boundingBox = await el.boundingBox();
@@ -21,14 +30,17 @@ export const dragElementBy = async (
const startX = startXCoord === undefined ? boundingBox.x + boundingBox.width / 2 : startXCoord;
const startY = startYCoord === undefined ? boundingBox.y + boundingBox.height / 2 : startYCoord;
const endX = startX + dragByX;
const endY = startY + dragByY;
// Navigate to the start position.
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.mouse.move(endX, endY, { steps: 10 });
await page.mouse.up();
// Drag the element.
await moveElement(page, startX, startY, dragByX, dragByY);
if (releaseDrag) {
await page.mouse.up();
}
};
/**
@@ -55,12 +67,83 @@ export const dragElementByYAxis = async (
const startX = boundingBox.x + boundingBox.width / 2;
const startY = startYCoord === undefined ? boundingBox.y + boundingBox.height / 2 : startYCoord;
// Navigate to the start position.
await page.mouse.move(startX, startY);
await page.mouse.down();
for (let i = 0; i < dragByY; i += 20) {
await page.mouse.move(startX, startY + i);
}
// Drag the element.
await moveElement(page, startX, startY, 0, dragByY);
await page.mouse.up();
};
const validateDragByX = (startX: number, dragByX: number, viewportWidth: number) => {
const endX = startX + dragByX;
// The element is being dragged past the right of the viewport.
if (endX > viewportWidth) {
const recommendedDragByX = viewportWidth - startX - 5;
throw new Error(
`The element is being dragged past the right of the viewport. Update the dragByX value to prevent going out of bounds. A recommended value is ${recommendedDragByX}.`
);
}
// The element is being dragged past the left of the viewport.
if (endX < 0) {
const recommendedDragByX = startX - 5;
throw new Error(
`The element is being dragged past the left of the viewport. Update the dragByX value to prevent going out of bounds. A recommended value is ${recommendedDragByX}.`
);
}
};
const validateDragByY = (startY: number, dragByY: number, viewportHeight: number) => {
const endY = startY + dragByY;
// The element is being dragged past the bottom of the viewport.
if (endY > viewportHeight) {
const recommendedDragByY = viewportHeight - startY - 5;
throw new Error(
`The element is being dragged past the bottom of the viewport. Update the dragByY value to prevent going out of bounds. A recommended value is ${recommendedDragByY}.`
);
}
// The element is being dragged past the top of the viewport.
if (endY < 0) {
const recommendedDragByY = startY - 5;
throw new Error(
`The element is being dragged past the top of the viewport. Update the dragByY value to prevent going out of bounds. A recommended value is ${recommendedDragByY}.`
);
}
};
const moveElement = async (page: E2EPage, startX: number, startY: number, dragByX = 0, dragByY = 0) => {
const steps = 10;
const browser = page.context().browser()!.browserType().name();
const viewport = page.viewportSize();
if (viewport === null) {
throw new Error(
'Cannot get viewport size. See https://playwright.dev/docs/api/class-page#page-viewport-size for more information'
);
}
validateDragByX(startX, dragByX, viewport.width);
validateDragByY(startY, dragByY, viewport.height);
const endX = startX + dragByX;
const endY = startY + dragByY;
// Drag the element.
for (let i = 1; i <= steps; i++) {
const middleX = startX + (endX - startX) * (i / steps);
const middleY = startY + (endY - startY) * (i / steps);
await page.mouse.move(middleX, middleY);
// Safari needs to wait for a repaint to occur before moving the mouse again.
if (browser === 'webkit' && i % 2 === 0) {
// Repainting every 2 steps is enough to keep the drag gesture smooth.
// Anything past 4 steps will cause the drag gesture to be flaky.
await page.evaluate(() => new Promise(requestAnimationFrame));
}
}
};

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.2.4](https://github.com/ionic-team/ionic-framework/compare/v7.2.3...v7.2.4) (2023-08-16)
**Note:** Version bump only for package @ionic/docs
## [7.2.3](https://github.com/ionic-team/ionic-framework/compare/v7.2.2...v7.2.3) (2023-08-09)
**Note:** Version bump only for package @ionic/docs
## [7.2.2](https://github.com/ionic-team/ionic-framework/compare/v7.2.1...v7.2.2) (2023-08-02)
**Note:** Version bump only for package @ionic/docs
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
**Note:** Version bump only for package @ionic/docs

View File

@@ -1,12 +1,12 @@
{
"name": "@ionic/docs",
"version": "7.2.1",
"version": "7.2.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/docs",
"version": "7.2.1",
"version": "7.2.4",
"license": "MIT"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
"version": "7.2.1",
"version": "7.2.4",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"types": "core.d.ts",

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