Compare commits

..

114 Commits

Author SHA1 Message Date
Liam DeBeasi
a63474a621 5.8.3 2021-10-07 16:50:46 -04:00
Liam DeBeasi
f98151c5d1 5.8.3 2021-10-07 20:50:28 +00:00
Ely Lucas
655631ddf0 fix(react): fix to regression in overlay hooks dimiss method (#24038)
resolves #24030
2021-10-07 15:18:10 -04:00
Liam DeBeasi
11332e446c merge release-5.8.2
5.8.2
2021-10-06 10:24:14 -04:00
Liam DeBeasi
fe9bec29d5 5.8.2 2021-10-06 14:05:57 +00:00
Liam DeBeasi
b1ffdadbc3 chore(): fix typo in feature request template (#24017) 2021-10-05 09:05:49 -04:00
Liam DeBeasi
077b915ad5 chore(): fix typo in bug template (#24016) 2021-10-05 09:04:38 -04:00
Ely Lucas
2c97712601 fix(react): overlay hooks memorised properly to prevent re-renders (#24010)
resolves #23741

Co-authored-by: Fabrice <fabrice@weinberg.me>
2021-10-05 08:44:40 -04:00
Robert Rhoades
f112ad4490 fix(angular): use initialize function when setting up ionic angular to avoid config errors (#24004)
resolves #22853

Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-10-04 10:21:48 -04:00
Liam DeBeasi
25eb8cdf98 fix(status-bar): tapping status bar correctly scrolls content to top (#24001)
resolves #20423

Co-authored-by: Hans Krywalsky <EinfachHans@users.noreply.github.com>
2021-09-30 18:37:47 -04:00
Mads Buchmann Frederiksen
7010fe97a7 docs(readme): fix broken link to CONTRIBUTE guide (#23982) 2021-09-27 10:35:28 -04:00
Amanda Smith
a26275378f fix(alert): made it easier to tell if alert is scrollable in MD mode (#23976) 2021-09-24 14:23:41 -05:00
Liam DeBeasi
3ca04197a4 fix(item-sliding): closing an item can no longer be interrupted (#23973)
resolves #23969
2021-09-23 16:08:33 -04:00
Liam DeBeasi
aa4ba890e9 fix(select-popover): non-scrollable popovers no longer have forced overscroll (#23972)
resolves #23971
2021-09-23 10:05:32 -04:00
Liam DeBeasi
bb126a02e8 merge release-5.8.1
5.8.1
2021-09-22 10:48:51 -04:00
Liam DeBeasi
598aaed4bf 5.8.1 2021-09-22 09:14:14 -04:00
Liam DeBeasi
3c1be89112 fix(angular): select method now has correct types (#23953)
resolves #23952
2021-09-22 08:51:33 -04:00
Amanda Smith
00269941ca docs(router): make root prop docs more descriptive (#23961) 2021-09-21 13:08:55 -05:00
Amanda Smith
e483034f3a docs(refresher): fix 'to to' in snapbackDuration (#23960) 2021-09-21 10:28:52 -05:00
amandaesmith3
53d64c1eb8 docs(title): fix typo in usage CSS example (#23957) 2021-09-21 08:18:31 -05:00
Liam DeBeasi
ae1325cee6 fix(label): only inherit color if color property is set on ion-item (#23944)
resolves #20125
2021-09-16 15:27:43 -04:00
Liam DeBeasi
8108edd876 fix(item-sliding): item-sliding accounts for multiple ion-item elements (#23943)
resolves #19312
2021-09-16 12:29:12 -04:00
Liam DeBeasi
874e791377 merge release-5.8.0
5.8.0
2021-09-15 11:37:22 -04:00
Liam DeBeasi
b104690192 chore(): add version name 2021-09-15 11:19:25 -04:00
Liam DeBeasi
57bc299dea 5.8.0 2021-09-15 15:16:21 +00:00
Liam DeBeasi
5f95f45e58 chore(overlays): run build for vue (#23931) 2021-09-15 11:05:29 -04:00
amandaesmith3
6f85e010c8 docs(process): remove old Slack channel reference (#23932) 2021-09-15 09:57:54 -05:00
Liam DeBeasi
bd96a81ff8 feat(action-sheet, loading, modal, picker, popover): pass HTML attributes to host element (#23929) 2021-09-15 10:02:19 -04:00
William Martin
73a1daf0aa feat(alert, toast): pass arbitrary HTML attributes to host element (#23891)
resolves #23825
2021-09-14 22:44:57 -04:00
Michael Chen
1e13429731 fix(react): modal now mounts child component independently of other modals (#23903)
resolves #23904
2021-09-13 15:29:14 -04:00
Liam DeBeasi
1ed9f07060 fix(angular): nested tabs now go to correct page (#23902)
resolves #23897
2021-09-09 14:06:43 -04:00
Liam DeBeasi
47829690b5 fix(tab-bar): safe area padding now added when slot="top" (#23895)
resolves #23893
2021-09-08 13:33:16 -04:00
Liam DeBeasi
8888e2bafd fix(header): role attribute can now be customized (#23888)
resolves #21327
2021-09-08 10:48:18 -04:00
Liam DeBeasi
e512fc1ecd merge release-5.7.0
5.7.0
2021-09-01 10:07:36 -04:00
Liam DeBeasi
a12d146c3e 5.7.0 2021-09-01 09:43:23 -04:00
Liam DeBeasi
a0229bc7b2 refactor(virtual-scroll): deprecate virtual scroll in favor of JS framework solutions (#23854) 2021-08-31 18:20:29 -04:00
William Martin
11fda41420 feat(slides): add IonicSlides module for Swiper migration, deprecate ion-slides (#23844)
backports #23447
2021-08-31 17:52:47 -04:00
Ikko Ashimine
33f0bcd437 chore(slides): fix typo in image slides example (#23838) 2021-08-30 10:15:12 -04:00
Liam DeBeasi
3c442228ff fix(vue): router guards are now fired correctly when written in a component (#23821)
resolves #23820
2021-08-26 10:40:48 -04:00
Liam DeBeasi
50b88b24c2 chore(): run build to update picker readme (#23822) 2021-08-25 18:57:26 -04:00
Sarah Drasner
9317f6eb41 docs(picker): add a simple picker example for Vue (#23818)
There was previously no example for a vue picker, this adds one.

closes #2053
2021-08-25 17:50:33 -04:00
Liam DeBeasi
9932e26a2e fix(label): label now only takes up as much space as needed when slotted (#23807)
resolves #23806
2021-08-24 10:25:12 -04:00
Toby Smith
02409f2abf fix(reorder-group): dragging reorder item to bottom no longer gives out of bounds index (#23797)
resolves #23796
2021-08-23 09:38:27 -04:00
Liam DeBeasi
864212b0f2 fix(alert): AlertButton role now has correct types (#23791) 2021-08-18 13:43:12 -04:00
Liam DeBeasi
34b150e5e7 merge release-5.6.14
5.6.14
2021-08-18 09:33:41 -04:00
Liam DeBeasi
e4c0023df2 5.6.14 2021-08-18 09:17:36 -04:00
Mark Chris Levy
f9415ef8a6 fix(nav): custom animation is now used correctly (#23779)
resolves #23777
2021-08-18 08:34:34 -04:00
William Martin
e0c4ad30be fix(item-sliding): prevent scrolling during slide gesture (#23774)
resolves #19564
2021-08-17 23:53:16 -04:00
Liam DeBeasi
621f4faa1a fix(vue): using router.go now shows correct view (#23773)
resolves #22563
2021-08-17 08:53:55 -04:00
Liam DeBeasi
6b18a89ac2 fix(back-button): MD ripple now accounts for --ripple-color (#23749)
resolves #23748
2021-08-09 16:21:38 -04:00
Jacob McKay
067e621bbc fix(img): correctly determine when to load image when scrolling quickly on slower devices (#23704)
resolves #23703
2021-08-09 16:18:53 -04:00
William Martin
f83768cafe build(commit): add husky and commitizen (#23714) 2021-08-06 10:00:11 -04:00
Liam DeBeasi
2d6e45e8d1 merge release-5.6.13
5.6.13
2021-08-04 10:25:48 -04:00
Liam DeBeasi
22b7413f51 5.6.13 2021-08-04 10:05:10 -04:00
Liam DeBeasi
4a64e97a3e fix(vue): tabs warning about user-provided router outlet change is now correctly logged (#23724)
resolves #23719
2021-08-04 09:55:05 -04:00
Evgeniy
8a941fd24c fix(checkbox, radio): change event interfaces correctly use TypeScript generics for value (#23044)
Co-authored-by: Liam DeBeasi <liamdebeasi@icloud.com>
2021-08-03 16:29:53 -04:00
Liam DeBeasi
fbe648406b chore(): bump ionicons version (#23717) 2021-08-03 09:41:40 -04:00
Liam DeBeasi
4edb5e2fed fix(gesture): onEnd now correctly fires even if the event target was removed from the DOM (#23713)
resolves #22819 

Co-authored-by: Falingorn <falingorn@users.noreply.github.com>
2021-08-02 13:47:27 -04:00
Denis
792864f8ab fix(item-sliding): opening item while other items are open no longer requires multiple swipes (#23683)
resolves #21579
2021-08-02 12:56:27 -04:00
William Martin
f2a05bed1e fix(react): add SSR check to IonTabs (#23696)
resolves #23651
2021-08-02 10:28:51 -04:00
Moritz Eck
caf0917623 docs(platform): add capacitor to method docs (#23688)
resolves #23687
2021-07-26 08:49:24 -04:00
Liam DeBeasi
fb260a9e09 fix(vue): improve accuracy of ion-page dev warning (#23677)
resolves #23675
2021-07-23 09:42:06 -04:00
Liam DeBeasi
80edb603c2 merge release-5.6.12
5.6.12
2021-07-21 09:36:29 -04:00
Liam DeBeasi
f70ed79f47 5.6.12 2021-07-21 09:21:15 -04:00
Ikko Ashimine
ae0a1a3deb chore(nav): fix typo in test comment (#23658) 2021-07-20 11:21:39 -04:00
Liam DeBeasi
d8a2db73e2 chore(): add emojis to issue template titles (#23648)
resolves #23647
2021-07-15 13:55:16 -04:00
Liam DeBeasi
86ece8f8b5 chore(): fix typo in config (#23645) 2021-07-15 11:36:25 -04:00
Liam DeBeasi
3016b79717 chore(): remove cli, docs, and support templates in favor of directing visitors to correct place url (#23644) 2021-07-15 10:00:21 -04:00
Liam DeBeasi
773bbcb211 fix(overlays): overlay interfaces are now exported from framework packages and documented (#23619)
resolves #22790
2021-07-15 08:50:50 -04:00
Liam DeBeasi
3134e0afcd chore(): fix form template typos (#23635) 2021-07-14 19:31:04 -04:00
Liam DeBeasi
6d94a27fb9 chore(): convert remaining issue templates to forms (#23634) 2021-07-14 18:54:18 -04:00
Liam DeBeasi
d2ca304c12 chore(): use supported form keys (#23633) 2021-07-14 16:26:48 -04:00
Liam DeBeasi
e35386a52d chore(): fix yaml errors (#23632) 2021-07-14 15:50:34 -04:00
Liam DeBeasi
d10d9f9f74 chore(): fix bug issue name (#23630) 2021-07-14 15:18:49 -04:00
Liam DeBeasi
c940bd18d2 chore(): use new github form template for bug reports (#23629) 2021-07-14 14:49:30 -04:00
Liam DeBeasi
174b7de741 docs(vue): add card style modal example (#23628) 2021-07-14 10:18:17 -04:00
Liam DeBeasi
3cebcb0883 chore(): warn if developer forgot to use ionpage component in view (#23625) 2021-07-14 08:59:31 -04:00
Liam DeBeasi
7315e0157b chore(): switch to using disallow terminology (#23618) 2021-07-13 14:03:58 -04:00
jcesarmobile
4b56744d7f docs(react): install @ionic/cli instead of ionic (#23610) 2021-07-12 14:39:18 -04:00
Liam DeBeasi
c08345df2e fix(menu-button): custom aria-label can now be set (#23608)
resolves #23604
2021-07-12 08:52:03 -04:00
Liam DeBeasi
fa069424b2 fix(router-outlet): improve reliability of swipe back gesture when quickly swiping back (#23527)
resolves #22895
2021-07-09 09:29:16 -04:00
Liam DeBeasi
3b803ebe02 fix(button): buttons are now disabled during page transitions (#23589)
resolves #23588
2021-07-09 09:27:11 -04:00
William Martin
9021e7cc4b fix(item): mirror disabled prop to aria attribute (#23544)
resolves #23513
2021-07-09 09:19:48 -04:00
Liam DeBeasi
39315bc857 fix(action-sheet): header, subheader, and icon alignment better matches native ios (#23322)
resolves #23317
2021-07-08 09:38:00 -04:00
omar2205
a15cace139 docs(loading): show how to use dismiss method returns from useIonLoading for react (#23537) 2021-07-07 09:04:10 -04:00
Liam DeBeasi
635ac195d9 docs(router-outlet): add react note to docs (#23580) 2021-07-06 10:19:54 -04:00
Liam DeBeasi
34aad178d0 merge release-5.6.11
5.6.11
2021-07-01 12:03:53 -04:00
Liam DeBeasi
cffeb4d9bd 5.6.11 2021-07-01 11:16:21 -04:00
Liam DeBeasi
69be51dc54 fix(ios, md): double tapping back button no longer causes app to go back 2 pages (#23526)
resolves #18455
2021-07-01 10:44:19 -04:00
Liam DeBeasi
f3d6abbc1b fix(animation): typescript interface has correct return value for progress methods (#23536) 2021-06-29 16:36:51 -04:00
Liam DeBeasi
0b5c470b98 docs(card): fix usage example for vue (#23535) 2021-06-29 15:03:01 -04:00
Liam DeBeasi
d5980354fa chore(): add link to v6 beta onboarding guide (#23495) 2021-06-23 09:31:15 -04:00
Liam DeBeasi
508f1a46fb chore(): add 6.x to bug report template (#23493) 2021-06-23 09:27:21 -04:00
Liam DeBeasi
3130dd3fd8 chore(): add 6.x to feature request template (#23494) 2021-06-23 09:26:25 -04:00
Liam DeBeasi
57156526ff merge release-5.6.10
5.6.10
2021-06-22 10:02:05 -04:00
Liam DeBeasi
40fadcd9bf 5.6.10 2021-06-22 09:30:43 -04:00
Liam DeBeasi
494a4a08fe chore(): add missing dependency (#23482) 2021-06-22 09:20:45 -04:00
Liam DeBeasi
b3847ff723 chore(): remove old test app, bump dependencies (#23481) 2021-06-22 08:43:57 -04:00
Liam DeBeasi
a2a4cff3d0 fix(vue): IonTabs can now accept IonRouterOutlet (#23477)
resolves #23321
2021-06-21 16:52:50 -04:00
Liam DeBeasi
68c0e7136d fix(button): buttons using fill and color properties now account for hover and focused opacity variables (#23442)
resolves #23441
2021-06-21 13:00:50 -04:00
Liam DeBeasi
87b4a42c96 merge release-5.6.9
5.6.9
2021-06-08 09:38:34 -04:00
Liam DeBeasi
e27b5b6ae3 fix(item): using multiple items with inputs no longer results in console warnings (#23429)
resolves #23427
2021-06-08 09:16:29 -04:00
Liam DeBeasi
10be62a71d 5.6.9 2021-06-08 08:58:49 -04:00
Liam DeBeasi
60bedb5599 fix(vue): prevent error from being thrown when testing on certain jest runners (#23421)
resolves #23397
2021-06-07 10:49:19 -04:00
Liam DeBeasi
f008628851 fix(vue): improve v-model integration for Vue 3.1.0+ (#23420) 2021-06-04 19:25:02 -04:00
Brandy Carney
82cfa55653 fix(title): inherit padding for iOS title in a toolbar (#23343)
resolves #23072
2021-06-03 11:28:57 -04:00
Hans Krywalsky
ae96563fb3 fix(modal): swipe to close modal is no longer swipeable on footer (#23401)
resolves #23398
2021-06-02 08:59:25 -04:00
Liam DeBeasi
d527414e10 chore(radio-group): clean up code to reuse helper function (#23396)
Co-authored-by: Daniel Simão <danielsimao@users.noreply.github.com>
2021-06-01 10:44:45 -04:00
Liam DeBeasi
6cc6f4c44b chore(): revert incorrect co-author credit (#23395)
This reverts commit 62ed9712e1.
2021-06-01 09:54:04 -04:00
Liam DeBeasi
62ed9712e1 chore(radio-group): use existing helper function for getting all radios (#23394)
Co-authored-by: Daniel Simão < danielsimao @users.noreply.github.com>
2021-06-01 09:22:12 -04:00
Liam DeBeasi
e3aaa9513e docs(popover): resolve variable naming conflict (#23393) 2021-06-01 09:08:14 -04:00
dejian-lc
e4bbaf8a7f chore(angular): fix typo in platform provider (#23385) 2021-06-01 08:52:36 -04:00
Victor Berchet
857550a0c4 chore(router): clean up code and add comments (#23355) 2021-05-28 08:57:52 -04:00
Liam DeBeasi
fee4e82f0e merge release-5.6.8
5.6.8
2021-05-27 16:01:52 -04:00
212 changed files with 8024 additions and 22275 deletions

View File

@@ -1,59 +0,0 @@
---
name: Bug Report
about: Create a report to help us improve
title: 'bug: '
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use the Ionic Forum: https://forum.ionicframework.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Bug Report
**Ionic version:**
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
[ ] **4.x**
[x] **5.x**
**Current behavior:**
<!-- Describe how the bug manifests. -->
**Expected behavior:**
<!-- Describe what the behavior would be without the bug. -->
**Steps to reproduce:**
<!-- Please explain the steps required to duplicate the issue, especially if you are able to provide a sample application. -->
**Related code:**
<!-- If you are able to illustrate the bug or feature request with an example, please provide a sample application via one of the following means:
A sample application via GitHub
StackBlitz (https://stackblitz.com)
Ionic Angular StackBlitz: https://stackblitz.com/edit/ionic-v4-angular-tabs
Plunker (http://plnkr.co/edit/cpeRJs?p=preview)
-->
```
insert short code snippets here
```
**Other information:**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->
**Ionic info:**
<!-- (run `ionic info` from a terminal/cmd prompt and paste output below): -->
```
insert the output from ionic info here
```

56
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: 🐛 Bug Report
description: Create a report to help us improve Ionic Framework
title: 'bug: '
body:
- type: checkboxes
attributes:
label: Prerequisites
description: Please ensure you have completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
required: true
- label: I agree to follow the [Code of Conduct](https://ionicframework.com/code-of-conduct).
required: true
- label: I have searched for [existing issues](https://github.com/ionic-team/ionic-framework/issues) that already report this problem, without success.
required: true
- type: checkboxes
attributes:
label: Ionic Framework Version
description: Please select which versions of Ionic Framework this issue impacts. For Ionic Framework 1.x issues, please use https://github.com/ionic-team/ionic-v1. For Ionic Framework 2.x and 3.x issues, please use https://github.com/ionic-team/ionic-v3.
options:
- label: v4.x
- label: v5.x
- label: v6.x
- type: textarea
attributes:
label: Current Behavior
description: A clear description of what the bug is and how it manifests.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: Please explain the steps required to duplicate this issue.
validations:
required: true
- type: input
attributes:
label: Code Reproduction URL
description: Please reproduce this issue in a blank Ionic Framework starter application and provide a link to the repo. Try out our [Getting Started Wizard](https://ionicframework.com/start#basics) to quickly spin up an Ionic Framework starter app. This is the best way to ensure this issue is triaged quickly. Issues without a code reproduction may be closed if the Ionic Team cannot reproduce the issue you are reporting.
placeholder: https://github.com/...
- type: textarea
attributes:
label: Ionic Info
description: Please run `ionic info` from within your Ionic Framework project directory and paste the output below.
validations:
requred: true
- type: textarea
attributes:
label: Additional Information
description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc.

View File

@@ -1,11 +0,0 @@
---
name: CLI
about: Suggest an improvement for the CLI
title: ''
labels: 'ionitron: cli'
assignees: ''
---
# CLI
Please do not submit bug reports or feature requests related to the Ionic CLI. Instead, please submit an issue to the [Ionic CLI Repository](https://github.com/ionic-team/ionic-cli/issues/new/choose).

10
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
contact_links:
- name: 📚 Documentation
url: https://github.com/ionic-team/ionic-docs/issues/new/choose
about: This issue tracker is not for documentation issues. Please file documentation issues on the Ionic Docs repo.
- name: 💻 CLI
url: https://github.com/ionic-team/ionic-cli/issues/new/choose
about: This issue tracker is not for CLI issues. Please file CLI issues on the Ionic CLI repo.
- name: 🤔 Support Question
url: https://forum.ionicframework.com/
about: This issue tracker is not for support questions. Please post your question on the Ionic Forums.

View File

@@ -1,11 +0,0 @@
---
name: Documentation
about: Suggest an improvement for the documentation of this project
title: ''
labels: 'ionitron: docs'
assignees: ''
---
# Documentation
Please do not submit issues on how to improve or fix the documentation. Instead, please submit an issue to the [Ionic Docs Repository](https://github.com/ionic-team/ionic-docs/issues/new/choose).

View File

@@ -1,37 +0,0 @@
---
name: Feature Request
about: Suggest an idea for this project
title: 'feat: '
labels: ''
assignees: ''
---
<!-- Before submitting an issue, please consult our docs (https://ionicframework.com/docs/). -->
<!-- Please make sure you are posting an issue pertaining to the Ionic Framework. If you are having an issue with the Ionic Appflow services (Ionic View, Ionic Deploy, etc.) please consult the Ionic Appflow support portal (https://ionic.zendesk.com/hc/en-us) -->
<!-- Please do not submit support requests or "How to" questions here. Instead, please use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/ -->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
# Feature Request
**Ionic version:**
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
[x] **4.x**
**Describe the Feature Request**
<!-- A clear and concise description of what the feature request is. Please include if your feature request is related to a problem. -->
**Describe Preferred Solution**
<!-- A clear and concise description of what you want to happen. -->
**Describe Alternatives**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Related Code**
<!-- If you are able to illustrate the feature request with an example, please provide a sample application via an online code collaborator such as [StackBlitz](https://stackblitz.com), or [GitHub](https://github.com). -->
**Additional Context**
<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to add, use case, Stack Overflow links, forum links, screenshots, OS if applicable, etc. -->

View File

@@ -0,0 +1,43 @@
name: 💡 Feature Request
description: Suggest an idea for Ionic Framework
title: 'feat: '
body:
- type: checkboxes
attributes:
label: Prerequisites
description: Please ensure you have completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#creating-an-issue).
required: true
- label: I agree to follow the [Code of Conduct](https://ionicframework.com/code-of-conduct).
required: true
- label: I have searched for [existing issues](https://github.com/ionic-team/ionic-framework/issues) that already include this feature request, without success.
required: true
- type: textarea
attributes:
label: Describe the Feature Request
description: A clear and concise description of what the feature does.
validations:
required: true
- type: textarea
attributes:
label: Describe the Use Case
description: A clear and concise use case for what problem this feature would solve.
validations:
required: true
- type: textarea
attributes:
label: Describe Preferred Solution
description: A clear and concise description of what you how you want this feature to be added to Ionic Framework.
- type: textarea
attributes:
label: Describe Alternatives
description: A clear and concise description of any alternative solutions or features you have considered.
- type: textarea
attributes:
label: Related Code
description: If you are able to illustrate the feature request with an example, please provide a sample Ionic Framework application. Try out our [Getting Started Wizard](https://ionicframework.com/start#basics) to quickly spin up an Ionic Framework starter app.
- type: textarea
attributes:
label: Additional Information
description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to implement, Stack Overflow links, forum links, etc.

View File

@@ -1,11 +0,0 @@
---
name: Support Question
about: Question on how to use this project
title: 'support: '
labels: 'ionitron: support'
assignees: ''
---
# Support Question
Please do not submit support requests or "How to" questions here. Instead, please use the Ionic Forum: https://forum.ionicframework.com/

2
.github/PROCESS.md vendored
View File

@@ -60,7 +60,7 @@ If the issue is associated with Ionic Appflow the submitter should be told to us
### Support Questions
If the issue is a support question, the submitter should be redirected to our [forum](https://forum.ionicframework.com) or [slack channel](https://ionicworldwide.herokuapp.com/). The issue should be closed and locked. Use the `ionitron: support` label to accomplish this.
If the issue is a support question, the submitter should be redirected to our [forum](https://forum.ionicframework.com). The issue should be closed and locked. Use the `ionitron: support` label to accomplish this.
### Incomplete Template

View File

@@ -1,3 +1,150 @@
## [5.8.3](https://github.com/ionic-team/ionic/compare/v5.8.2...v5.8.3) (2021-10-07)
### Bug Fixes
* **react:** overlay hooks dismiss method now works ([#24038](https://github.com/ionic-team/ionic/issues/24038)) ([655631d](https://github.com/ionic-team/ionic/commit/655631ddf059ce58066d5384d0ae186d7abc09a9)), closes [#24030](https://github.com/ionic-team/ionic/issues/24030)
## [5.8.2](https://github.com/ionic-team/ionic/compare/v5.8.1...v5.8.2) (2021-10-06)
### Bug Fixes
* **alert:** made it easier to tell if alert is scrollable in MD mode ([#23976](https://github.com/ionic-team/ionic/issues/23976)) ([a262753](https://github.com/ionic-team/ionic/commit/a26275378f10835343ad8a6cdea50303e6c10a14))
* **angular:** use initialize function when setting up ionic angular to avoid config errors ([#24004](https://github.com/ionic-team/ionic/issues/24004)) ([f112ad4](https://github.com/ionic-team/ionic/commit/f112ad4490dc4a179dc3feab495530e14e655e5a)), closes [#22853](https://github.com/ionic-team/ionic/issues/22853)
* **item-sliding:** closing an item can no longer be interrupted ([#23973](https://github.com/ionic-team/ionic/issues/23973)) ([3ca0419](https://github.com/ionic-team/ionic/commit/3ca04197a4186c85d04cdf04fa9cb2689ca1bbfb)), closes [#23969](https://github.com/ionic-team/ionic/issues/23969)
* **react:** overlay hooks memorised properly to prevent re-renders ([#24010](https://github.com/ionic-team/ionic/issues/24010)) ([2c97712](https://github.com/ionic-team/ionic/commit/2c977126012ae0231d4e4fa63cc76a528bde699b)), closes [#23741](https://github.com/ionic-team/ionic/issues/23741)
* **select-popover:** non-scrollable popovers no longer have forced overscroll ([#23972](https://github.com/ionic-team/ionic/issues/23972)) ([aa4ba89](https://github.com/ionic-team/ionic/commit/aa4ba890e9c18e8a911c5188b3e2e85433658be9)), closes [#23971](https://github.com/ionic-team/ionic/issues/23971)
* **status-bar:** tapping status bar correctly scrolls content to top ([#24001](https://github.com/ionic-team/ionic/issues/24001)) ([25eb8cd](https://github.com/ionic-team/ionic/commit/25eb8cdf98fe455433ca6185e89d9e1223a6d3ae)), closes [#20423](https://github.com/ionic-team/ionic/issues/20423)
## [5.8.1](https://github.com/ionic-team/ionic/compare/v5.8.0...v5.8.1) (2021-09-22)
### Bug Fixes
* **angular:** select method now has correct types ([#23953](https://github.com/ionic-team/ionic/issues/23953)) ([3c1be89](https://github.com/ionic-team/ionic/commit/3c1be89112d464e77d65c875223138aaedf350cd)), closes [#23952](https://github.com/ionic-team/ionic/issues/23952)
* **item-sliding:** item-sliding accounts for multiple ion-item elements ([#23943](https://github.com/ionic-team/ionic/issues/23943)) ([8108edd](https://github.com/ionic-team/ionic/commit/8108edd876b10834015016385dc3cd5b8f31fbfa)), closes [#19312](https://github.com/ionic-team/ionic/issues/19312)
* **label:** only inherit color if color property is set on ion-item ([#23944](https://github.com/ionic-team/ionic/issues/23944)) ([ae1325c](https://github.com/ionic-team/ionic/commit/ae1325cee698066a71aae4e7deb953c4185c0926)), closes [#20125](https://github.com/ionic-team/ionic/issues/20125)
# [5.8.0 Calcium](https://github.com/ionic-team/ionic/compare/v5.7.0...v5.8.0) (2021-09-15)
### Bug Fixes
* **angular:** nested tabs now go to correct page ([#23902](https://github.com/ionic-team/ionic/issues/23902)) ([1ed9f07](https://github.com/ionic-team/ionic/commit/1ed9f07060736d0c951910427fb12b250d7dd9af)), closes [#23897](https://github.com/ionic-team/ionic/issues/23897)
* **header:** role attribute can now be customized ([#23888](https://github.com/ionic-team/ionic/issues/23888)) ([8888e2b](https://github.com/ionic-team/ionic/commit/8888e2bafd76b59f32b932b5d4a6a961b52894d9)), closes [#21327](https://github.com/ionic-team/ionic/issues/21327)
* **react:** modal now mounts child component independently of other modals ([#23903](https://github.com/ionic-team/ionic/issues/23903)) ([1e13429](https://github.com/ionic-team/ionic/commit/1e13429731c1d4b5200af7f5ca20aff1f3078bfe)), closes [#23904](https://github.com/ionic-team/ionic/issues/23904)
* **tab-bar:** safe area padding now added when slot="top" ([#23895](https://github.com/ionic-team/ionic/issues/23895)) ([4782969](https://github.com/ionic-team/ionic/commit/47829690b538903b70ad4fe77657404013270263)), closes [#23893](https://github.com/ionic-team/ionic/issues/23893)
### Features
* **action-sheet, loading, modal, picker, popover:** pass HTML attributes to host element ([#23929](https://github.com/ionic-team/ionic/issues/23929)) ([bd96a81](https://github.com/ionic-team/ionic/commit/bd96a81ff80ffe32914804ba9b6234c0286a33db))
* **alert, toast:** pass arbitrary HTML attributes to host element ([#23891](https://github.com/ionic-team/ionic/issues/23891)) ([73a1daf](https://github.com/ionic-team/ionic/commit/73a1daf0aaf6ffe8c7871619f2aec5f6fca1321a)), closes [#23825](https://github.com/ionic-team/ionic/issues/23825)
# [5.7.0 Potassium](https://github.com/ionic-team/ionic/compare/v5.6.14...v5.7.0) (2021-09-01)
### Bug Fixes
* **alert:** AlertButton role now has correct types ([#23791](https://github.com/ionic-team/ionic/issues/23791)) ([864212b](https://github.com/ionic-team/ionic/commit/864212b0f28d33daede5f4767aa03efa37c219ae))
* **label:** label now only takes up as much space as needed when slotted ([#23807](https://github.com/ionic-team/ionic/issues/23807)) ([9932e26](https://github.com/ionic-team/ionic/commit/9932e26a2ef28317bc85761e71a8fc4d881b8ae8)), closes [#23806](https://github.com/ionic-team/ionic/issues/23806)
* **reorder-group:** dragging reorder item to bottom no longer gives out of bounds index ([#23797](https://github.com/ionic-team/ionic/issues/23797)) ([02409f2](https://github.com/ionic-team/ionic/commit/02409f2abfa8acbab05d0f1217b9d1c13721746e)), closes [#23796](https://github.com/ionic-team/ionic/issues/23796)
* **vue:** router guards are now fire correctly when written in a component ([#23821](https://github.com/ionic-team/ionic/issues/23821)) ([3c44222](https://github.com/ionic-team/ionic/commit/3c442228ff746165fd823687a2661a24edd08820)), closes [#23820](https://github.com/ionic-team/ionic/issues/23820)
### Features
* **slides:** add IonicSlides module for Swiper migration, deprecate ion-slides ([#23844](https://github.com/ionic-team/ionic/issues/23844)) ([11fda41](https://github.com/ionic-team/ionic/commit/11fda41420343886dabd97096690be38f1c40524)), closes [#23447](https://github.com/ionic-team/ionic/issues/23447)
### Code Refactoring
* **virtual-scroll:** deprecated virtual scroll in favor of solutions provided by JS frameworks ([#23854](https://github.com/ionic-team/ionic-framework/pull/23854)) ([a0229bc](https://github.com/ionic-team/ionic-framework/commit/a0229bc7b2edb061510de0f2042e7910d04accc0))
## [5.6.14](https://github.com/ionic-team/ionic/compare/v5.6.13...v5.6.14) (2021-08-18)
### Bug Fixes
* **back-button:** MD ripple now accounts for --ripple-color ([#23749](https://github.com/ionic-team/ionic/issues/23749)) ([6b18a89](https://github.com/ionic-team/ionic/commit/6b18a89ac2c446082ce7faebe329157eedb13a0e)), closes [#23748](https://github.com/ionic-team/ionic/issues/23748)
* **img:** correctly determine when to load image when scrolling quickly on slower devices ([#23704](https://github.com/ionic-team/ionic/issues/23704)) ([067e621](https://github.com/ionic-team/ionic/commit/067e621bbc3865184ae114b8c91122188c13c860)), closes [#23703](https://github.com/ionic-team/ionic/issues/23703)
* **item-sliding:** prevent scrolling during slide gesture ([#23774](https://github.com/ionic-team/ionic/issues/23774)) ([e0c4ad3](https://github.com/ionic-team/ionic/commit/e0c4ad30bec3f2bd325d65b210ffb0437149810f)), closes [#19564](https://github.com/ionic-team/ionic/issues/19564)
* **nav:** custom animation is now used correctly ([#23779](https://github.com/ionic-team/ionic/issues/23779)) ([f9415ef](https://github.com/ionic-team/ionic/commit/f9415ef8a689e26078bdd01623348c79f9f818ad)), closes [#23777](https://github.com/ionic-team/ionic/issues/23777)
* **vue:** using router.go now shows correct view ([#23773](https://github.com/ionic-team/ionic/issues/23773)) ([621f4fa](https://github.com/ionic-team/ionic/commit/621f4faa1ab03137158127a56c7fe0aa1f7ae489)), closes [#22563](https://github.com/ionic-team/ionic/issues/22563)
## [5.6.13](https://github.com/ionic-team/ionic/compare/v5.6.12...v5.6.13) (2021-08-04)
### Bug Fixes
* **checkbox, radio:** change event interfaces correctly use TypeScript generics for value ([#23044](https://github.com/ionic-team/ionic/issues/23044)) ([8a941fd](https://github.com/ionic-team/ionic/commit/8a941fd24cd138817a2e91c42898878a919538e4))
* **gesture:** onEnd now correctly fires even if the event target was removed from the DOM ([#23713](https://github.com/ionic-team/ionic/issues/23713)) ([4edb5e2](https://github.com/ionic-team/ionic/commit/4edb5e2fed55c8ea21eae50821d16d351bf3aebf)), closes [#22819](https://github.com/ionic-team/ionic/issues/22819)
* **item-sliding:** opening item while other items are open no longer requires multiple swipes ([#23683](https://github.com/ionic-team/ionic/issues/23683)) ([792864f](https://github.com/ionic-team/ionic/commit/792864f8ab21dc178c1836a8a0d4fe2d305cc142)), closes [#21579](https://github.com/ionic-team/ionic/issues/21579)
* **react:** IonTabs no longer causes SSR to fail ([#23696](https://github.com/ionic-team/ionic/issues/23696)) ([f2a05be](https://github.com/ionic-team/ionic/commit/f2a05bed1e2a1150e8f1823bfed2d12a219d6ad0)), closes [#23651](https://github.com/ionic-team/ionic/issues/23651)
* **vue:** improve accuracy of ion-page dev warning ([#23677](https://github.com/ionic-team/ionic/issues/23677)) ([fb260a9](https://github.com/ionic-team/ionic/commit/fb260a9e09e6f3912b30ef2ebf581d3216483fea)), closes [#23675](https://github.com/ionic-team/ionic/issues/23675)
* **vue:** tabs warning about user-provided router outlet change is now correctly logged ([#23724](https://github.com/ionic-team/ionic/issues/23724)) ([4a64e97](https://github.com/ionic-team/ionic/commit/4a64e97a3e390e365101bbb477acad0ddc4671ff)), closes [#23719](https://github.com/ionic-team/ionic/issues/23719)
## [5.6.12](https://github.com/ionic-team/ionic/compare/v5.6.11...v5.6.12) (2021-07-21)
### Bug Fixes
* **action-sheet:** header, subheader, and icon alignment better matches native ios ([#23322](https://github.com/ionic-team/ionic/issues/23322)) ([39315bc](https://github.com/ionic-team/ionic/commit/39315bc857b850347dca386776665e21c9742cad)), closes [#23317](https://github.com/ionic-team/ionic/issues/23317)
* **button:** buttons are now disabled during page transitions ([#23589](https://github.com/ionic-team/ionic/issues/23589)) ([3b803eb](https://github.com/ionic-team/ionic/commit/3b803ebe024be3dbcf814a30a18df51ce23c8880)), closes [#23588](https://github.com/ionic-team/ionic/issues/23588)
* **item:** mirror disabled prop to aria attribute ([#23544](https://github.com/ionic-team/ionic/issues/23544)) ([9021e7c](https://github.com/ionic-team/ionic/commit/9021e7cc4b48a69ccc94faa7d2ddcb10a2afa340)), closes [#23513](https://github.com/ionic-team/ionic/issues/23513)
* **menu-button:** custom aria-label can now be set ([#23608](https://github.com/ionic-team/ionic/issues/23608)) ([c08345d](https://github.com/ionic-team/ionic/commit/c08345df2ee3175f3f0d11ff877c7b6f1a102321)), closes [#23604](https://github.com/ionic-team/ionic/issues/23604)
* **overlays:** overlay interfaces are now exported from framework packages and documented ([#23619](https://github.com/ionic-team/ionic/issues/23619)) ([773bbcb](https://github.com/ionic-team/ionic/commit/773bbcb211d3cf0caf38c25b44e666d98ddfafe5)), closes [#22790](https://github.com/ionic-team/ionic/issues/22790)
* **router-outlet:** improve reliability of swipe back gesture when quickly swiping back ([#23527](https://github.com/ionic-team/ionic/issues/23527)) ([fa06942](https://github.com/ionic-team/ionic/commit/fa069424b265891852a07869b6d086a1cb041e93)), closes [#22895](https://github.com/ionic-team/ionic/issues/22895)
## [5.6.11](https://github.com/ionic-team/ionic/compare/v5.6.10...v5.6.11) (2021-07-01)
### Bug Fixes
* **animation:** typescript interface has correct return value for progress methods ([#23536](https://github.com/ionic-team/ionic/issues/23536)) ([f3d6abb](https://github.com/ionic-team/ionic/commit/f3d6abbc1beeafe3b5e7f473d70d0b8ef4c79bc8))
* **ios, md:** double tapping back button no longer causes app to go back 2 pages ([#23526](https://github.com/ionic-team/ionic/issues/23526)) ([69be51d](https://github.com/ionic-team/ionic/commit/69be51dc54e670b2f75cbfac28a4a09517dbf355)), closes [#18455](https://github.com/ionic-team/ionic/issues/18455)
## [5.6.10](https://github.com/ionic-team/ionic/compare/v5.6.9...v5.6.10) (2021-06-22)
### Bug Fixes
* **button:** buttons using fill and color properties now account for hover and focused opacity variables ([#23442](https://github.com/ionic-team/ionic/issues/23442)) ([68c0e71](https://github.com/ionic-team/ionic/commit/68c0e7136d3f8aad8a195a0371104f7dd5fa7060)), closes [#23441](https://github.com/ionic-team/ionic/issues/23441)
* **item:** using multiple items with inputs no longer results in console warnings ([#23429](https://github.com/ionic-team/ionic/issues/23429)) ([e27b5b6](https://github.com/ionic-team/ionic/commit/e27b5b6ae360c44d8521ac7191817cbbe0367c05)), closes [#23427](https://github.com/ionic-team/ionic/issues/23427)
* **vue:** IonTabs can now accept IonRouterOutlet, deprecated default router outlet in tabs ([#23477](https://github.com/ionic-team/ionic/issues/23477)) ([a2a4cff](https://github.com/ionic-team/ionic/commit/a2a4cff3d0d67868f384e1e9eec7cc738e260a27)), closes [#23321](https://github.com/ionic-team/ionic/issues/23321)
## [5.6.9](https://github.com/ionic-team/ionic/compare/v5.6.8...v5.6.9) (2021-06-08)
### Bug Fixes
* **modal:** swipe to close modal is no longer swipeable on footer ([#23401](https://github.com/ionic-team/ionic/issues/23401)) ([ae96563](https://github.com/ionic-team/ionic/commit/ae96563fb3c4612cb8585292b389ee746f5759f7)), closes [#23398](https://github.com/ionic-team/ionic/issues/23398)
* **title:** inherit padding for iOS title in a toolbar ([#23343](https://github.com/ionic-team/ionic/issues/23343)) ([82cfa55](https://github.com/ionic-team/ionic/commit/82cfa5565347704b0e9f7dac792ed2aa6dd30505)), closes [#23072](https://github.com/ionic-team/ionic/issues/23072)
* **vue:** improve v-model integration for Vue 3.1.0+ ([#23420](https://github.com/ionic-team/ionic/issues/23420)) ([f008628](https://github.com/ionic-team/ionic/commit/f0086288512bd7f7d1929d79bfd8bf702efc732e))
* **vue:** prevent error from being thrown when testing on certain jest runners ([#23421](https://github.com/ionic-team/ionic/issues/23421)) ([60bedb5](https://github.com/ionic-team/ionic/commit/60bedb5599b286bffccfc54c4861a269d9b8df73)), closes [#23397](https://github.com/ionic-team/ionic/issues/23397)
## [5.6.8](https://github.com/ionic-team/ionic/compare/v5.6.7...v5.6.8) (2021-05-27)
@@ -3901,4 +4048,4 @@ The following dependencies need to be updated to resolve build errors
<a name="0.1.0"></a>
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)
## [0.1.0](https://github.com/ionic-team/ionic/commit/43a8c4c7a719169336a84964fc1c737562d764a6) (2018-03-01)

View File

@@ -5,6 +5,9 @@ build top quality native and progressive web apps with web technologies.
Ionic Framework is based on [Web Components](https://www.webcomponents.org/introduction) and comes with many significant performance, usability, and feature improvements over the past versions.
## Looking for the Ionic Framework v6 beta?
[Click here to get started!](https://github.com/ionic-team/ionic-framework/blob/next/BETA.md)
### Packages

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular",
"version": "5.6.8",
"version": "5.8.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular",
"version": "5.6.8",
"version": "5.8.3",
"license": "MIT",
"dependencies": {
"@ionic/core": "5.6.7",
"@ionic/core": "5.8.2",
"tslib": "^1.9.3"
},
"devDependencies": {
@@ -204,12 +204,12 @@
}
},
"node_modules/@ionic/core": {
"version": "5.6.7",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.7.tgz",
"integrity": "sha512-bLH1sS2DI+C8trfYe/L96G2y+hJ9fK/azrNqGvGwHQAPy2li89DldbH+wPqe/Wclru8ZaWjRv35AyLBawixC2w==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.8.2.tgz",
"integrity": "sha512-BWIh6hyhq+tzVvebPMfRa+IhTV5/yXh4wO3a0U3Qo4PL4KDzWyBJfoiPi6bOEc+BAlFnCtOooTTXTumgXXOojg==",
"dependencies": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.1",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
}
},
@@ -297,9 +297,9 @@
}
},
"node_modules/@stencil/core": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.5.0.tgz",
"integrity": "sha512-gpoYJEYzu5LV2hr7uPZklug3zXhEbYGKyNodPfmOOYZtO9q42l7RQ3cAnC8MzEoF4jFrfemgtevGik8sqn9ClQ==",
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.6.0.tgz",
"integrity": "sha512-QsxWayZyusnqSZrlCl81R71rA3KqFjVVQSH4E0rGN15F1GdQaFonKlHLyCOLKLig1zzC+DQkLLiUuocexuvdeQ==",
"bin": {
"stencil": "bin/stencil"
},
@@ -2033,9 +2033,9 @@
}
},
"node_modules/ionicons": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"dependencies": {
"@stencil/core": "^2.5.0"
}
@@ -5156,12 +5156,12 @@
}
},
"@ionic/core": {
"version": "5.6.7",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.6.7.tgz",
"integrity": "sha512-bLH1sS2DI+C8trfYe/L96G2y+hJ9fK/azrNqGvGwHQAPy2li89DldbH+wPqe/Wclru8ZaWjRv35AyLBawixC2w==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.8.2.tgz",
"integrity": "sha512-BWIh6hyhq+tzVvebPMfRa+IhTV5/yXh4wO3a0U3Qo4PL4KDzWyBJfoiPi6bOEc+BAlFnCtOooTTXTumgXXOojg==",
"requires": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.1",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
},
"dependencies": {
@@ -5243,9 +5243,9 @@
"dev": true
},
"@stencil/core": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.5.0.tgz",
"integrity": "sha512-gpoYJEYzu5LV2hr7uPZklug3zXhEbYGKyNodPfmOOYZtO9q42l7RQ3cAnC8MzEoF4jFrfemgtevGik8sqn9ClQ=="
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.6.0.tgz",
"integrity": "sha512-QsxWayZyusnqSZrlCl81R71rA3KqFjVVQSH4E0rGN15F1GdQaFonKlHLyCOLKLig1zzC+DQkLLiUuocexuvdeQ=="
},
"@szmarczak/http-timer": {
"version": "1.1.2",
@@ -6662,9 +6662,9 @@
"dev": true
},
"ionicons": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"requires": {
"@stencil/core": "^2.5.0"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "5.6.8",
"version": "5.8.3",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -42,7 +42,7 @@
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"dependencies": {
"@ionic/core": "5.6.8",
"@ionic/core": "5.8.3",
"tslib": "^1.9.3"
},
"peerDependencies": {

View File

@@ -1,4 +1,5 @@
import { NgZone } from '@angular/core';
import { initialize } from '@ionic/core';
import { applyPolyfills, defineCustomElements } from '@ionic/core/loader';
import { Config } from './providers/config';
@@ -9,12 +10,11 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
return (): any => {
const win: IonicWindow | undefined = doc.defaultView as any;
if (win && typeof (window as any) !== 'undefined') {
const Ionic = win.Ionic = win.Ionic || {};
Ionic.config = {
initialize({
...config,
_zoneGate: (h: any) => zone.run(h)
};
});
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
? '__zone_symbol__addEventListener'

View File

@@ -86,10 +86,23 @@ export class IonTabs {
* b. If the last route view doesn't exist, then navigate
* to the default tabRootUrl
*/
@HostListener('ionTabButtonClick', ['$event.detail.tab'])
select(tab: string) {
@HostListener('ionTabButtonClick', ['$event'])
select(tabOrEvent: string | CustomEvent) {
const isTabString = typeof tabOrEvent === 'string';
const tab = (isTabString) ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
const alreadySelected = this.outlet.getActiveStackId() === tab;
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
/**
* If this is a nested tab, prevent the event
* from bubbling otherwise the outer tabs
* will respond to this event too, causing
* the app to get directed to the wrong place.
*/
if (!isTabString) {
(tabOrEvent as CustomEvent).stopPropagation();
}
if (alreadySelected) {
const activeStackId = this.outlet.getActiveStackId();
const activeView = this.outlet.getLastRouteView(activeStackId);

View File

@@ -43,7 +43,47 @@ export * from './types/ionic-lifecycle-hooks';
export { IonicModule } from './ionic-module';
// UTILS
export { IonicSafeString, getPlatforms, isPlatform, createAnimation } from '@ionic/core';
export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core';
// CORE TYPES
export { Animation, AnimationBuilder, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrames, AnimationLifecycle, Gesture, GestureConfig, GestureDetail, mdTransitionAnimation, iosTransitionAnimation, NavComponentWithProps } from '@ionic/core';
export {
Animation,
AnimationBuilder,
AnimationCallbackOptions,
AnimationDirection,
AnimationFill,
AnimationKeyFrames,
AnimationLifecycle,
Gesture,
GestureConfig,
GestureDetail,
mdTransitionAnimation,
iosTransitionAnimation,
NavComponentWithProps,
SpinnerTypes,
ActionSheetOptions,
ActionSheetButton,
AlertOptions,
AlertInput,
AlertTextareaAttributes,
AlertInputAttributes,
AlertButton,
LoadingOptions,
ModalOptions,
PickerOptions,
PickerButton,
PickerColumn,
PickerColumnOption,
PopoverOptions,
ToastOptions,
ToastButton
} from '@ionic/core';

View File

@@ -110,6 +110,7 @@ export class Platform {
* | Platform Name | Description |
* |-----------------|------------------------------------|
* | android | on a device running Android. |
* | capacitor | on a device running Capacitor. |
* | cordova | on a device running Cordova. |
* | ios | on a device running iOS. |
* | ipad | on an iPad device. |
@@ -209,7 +210,7 @@ export class Platform {
}
/**
* Returns `true` if the app is in portait mode.
* Returns `true` if the app is in portrait mode.
*/
isPortrait(): boolean {
return this.win.matchMedia && this.win.matchMedia('(orientation: portrait)').matches;

3
commitlint.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
extends: ['@commitlint/config-conventional']
}

View File

@@ -254,7 +254,7 @@ rules:
- visibility
- z-index
property-blacklist:
property-disallowed-list:
- background-position
- right
- left

View File

@@ -60,7 +60,7 @@ Notice how `IonBadge` is imported from `@ionic/core/components/ion-badge` rather
## How to contribute
[Check out the CONTRIBUTE guide](CONTRIBUTING.md)
[Check out the CONTRIBUTE guide](/.github/CONTRIBUTING.md)
## Related

View File

@@ -6,6 +6,7 @@ ion-action-sheet,prop,buttons,(string | ActionSheetButton)[],[],false,false
ion-action-sheet,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-action-sheet,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-action-sheet,prop,header,string | undefined,undefined,false,false
ion-action-sheet,prop,htmlAttributes,ActionSheetAttributes | undefined,undefined,false,false
ion-action-sheet,prop,keyboardClose,boolean,true,false,false
ion-action-sheet,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-action-sheet,prop,mode,"ios" | "md",undefined,false,false
@@ -50,6 +51,7 @@ ion-alert,prop,buttons,(string | AlertButton)[],[],false,false
ion-alert,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-alert,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-alert,prop,header,string | undefined,undefined,false,false
ion-alert,prop,htmlAttributes,AlertAttributes | undefined,undefined,false,false
ion-alert,prop,inputs,AlertInput[],[],false,false
ion-alert,prop,keyboardClose,boolean,true,false,false
ion-alert,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
@@ -230,7 +232,7 @@ ion-checkbox,prop,mode,"ios" | "md",undefined,false,false
ion-checkbox,prop,name,string,this.inputId,false,false
ion-checkbox,prop,value,string,'on',false,false
ion-checkbox,event,ionBlur,void,true
ion-checkbox,event,ionChange,CheckboxChangeEventDetail,true
ion-checkbox,event,ionChange,CheckboxChangeEventDetail<any>,true
ion-checkbox,event,ionFocus,void,true
ion-checkbox,css-prop,--background
ion-checkbox,css-prop,--background-checked
@@ -333,7 +335,7 @@ ion-datetime,prop,monthShortNames,string | string[] | undefined,undefined,false,
ion-datetime,prop,monthValues,number | number[] | string | undefined,undefined,false,false
ion-datetime,prop,name,string,this.inputId,false,false
ion-datetime,prop,pickerFormat,string | undefined,undefined,false,false
ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; showBackdrop?: boolean | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: Mode | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
ion-datetime,prop,pickerOptions,undefined | { columns?: PickerColumn[] | undefined; buttons?: PickerButton[] | undefined; cssClass?: string | string[] | undefined; showBackdrop?: boolean | undefined; backdropDismiss?: boolean | undefined; animated?: boolean | undefined; mode?: Mode | undefined; keyboardClose?: boolean | undefined; id?: string | undefined; htmlAttributes?: PickerAttributes | undefined; enterAnimation?: AnimationBuilder | undefined; leaveAnimation?: AnimationBuilder | undefined; },undefined,false,false
ion-datetime,prop,placeholder,null | string | undefined,undefined,false,false
ion-datetime,prop,readonly,boolean,false,false,false
ion-datetime,prop,value,null | string | undefined,undefined,false,false
@@ -621,6 +623,7 @@ ion-loading,prop,backdropDismiss,boolean,false,false,false
ion-loading,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-loading,prop,duration,number,0,false,false
ion-loading,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-loading,prop,htmlAttributes,LoadingAttributes | undefined,undefined,false,false
ion-loading,prop,keyboardClose,boolean,true,false,false
ion-loading,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-loading,prop,message,IonicSafeString | string | undefined,undefined,false,false
@@ -708,6 +711,7 @@ ion-modal,prop,component,Function | HTMLElement | null | string,undefined,true,f
ion-modal,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
ion-modal,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-modal,prop,htmlAttributes,ModalAttributes | undefined,undefined,false,false
ion-modal,prop,keyboardClose,boolean,true,false,false
ion-modal,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-modal,prop,mode,"ios" | "md",undefined,false,false
@@ -776,6 +780,7 @@ ion-picker,prop,columns,PickerColumn[],[],false,false
ion-picker,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-picker,prop,duration,number,0,false,false
ion-picker,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-picker,prop,htmlAttributes,PickerAttributes | undefined,undefined,false,false
ion-picker,prop,keyboardClose,boolean,true,false,false
ion-picker,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-picker,prop,mode,"ios" | "md",undefined,false,false
@@ -811,6 +816,7 @@ ion-popover,prop,componentProps,undefined | { [key: string]: any; },undefined,fa
ion-popover,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-popover,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-popover,prop,event,any,undefined,false,false
ion-popover,prop,htmlAttributes,PopoverAttributes | undefined,undefined,false,false
ion-popover,prop,keyboardClose,boolean,true,false,false
ion-popover,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-popover,prop,mode,"ios" | "md",undefined,false,false
@@ -867,7 +873,7 @@ ion-radio-group,none
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
ion-radio-group,prop,name,string,this.inputId,false,false
ion-radio-group,prop,value,any,undefined,false,false
ion-radio-group,event,ionChange,RadioGroupChangeEventDetail,true
ion-radio-group,event,ionChange,RadioGroupChangeEventDetail<any>,true
ion-range,shadow
ion-range,prop,color,string | undefined,undefined,false,true
@@ -1268,6 +1274,7 @@ ion-toast,prop,cssClass,string | string[] | undefined,undefined,false,false
ion-toast,prop,duration,number,0,false,false
ion-toast,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-toast,prop,header,string | undefined,undefined,false,false
ion-toast,prop,htmlAttributes,ToastAttributes | undefined,undefined,false,false
ion-toast,prop,keyboardClose,boolean,false,false,false
ion-toast,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-toast,prop,message,IonicSafeString | string | undefined,undefined,false,false

32
core/package-lock.json generated
View File

@@ -1,16 +1,16 @@
{
"name": "@ionic/core",
"version": "5.6.8",
"version": "5.8.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/core",
"version": "5.6.8",
"version": "5.8.3",
"license": "MIT",
"dependencies": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.1",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
},
"devDependencies": {
@@ -19,7 +19,7 @@
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/sass": "1.3.2",
"@stencil/vue-output-target": "^0.4.2",
"@stencil/vue-output-target": "^0.4.3",
"@types/jest": "^26.0.20",
"@types/node": "^14.6.0",
"@types/puppeteer": "5.4.3",
@@ -1374,9 +1374,9 @@
"dev": true
},
"node_modules/@stencil/vue-output-target": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.4.2.tgz",
"integrity": "sha512-C+HYpVXpYUpD0x8eFC0Ahe45D3ZOUpMAh/RDCXsgooi1auWTaOFvA7YkXHpc6suBkh44HnPhYEA1VIslpU4QEA==",
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.4.3.tgz",
"integrity": "sha512-+oTTSjzISERzrBDrtu3Iyhv69SSwzauQGnAej7GAWbLhzp/rCMyMHOTnZe5V+niJH9SHh1VahaVc3NQsA251qw==",
"dev": true,
"peerDependencies": {
"@stencil/core": ">=1.8.0"
@@ -5532,9 +5532,9 @@
}
},
"node_modules/ionicons": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"dependencies": {
"@stencil/core": "^2.5.0"
}
@@ -15022,9 +15022,9 @@
"dev": true
},
"@stencil/vue-output-target": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.4.2.tgz",
"integrity": "sha512-C+HYpVXpYUpD0x8eFC0Ahe45D3ZOUpMAh/RDCXsgooi1auWTaOFvA7YkXHpc6suBkh44HnPhYEA1VIslpU4QEA==",
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.4.3.tgz",
"integrity": "sha512-+oTTSjzISERzrBDrtu3Iyhv69SSwzauQGnAej7GAWbLhzp/rCMyMHOTnZe5V+niJH9SHh1VahaVc3NQsA251qw==",
"dev": true
},
"@stylelint/postcss-css-in-js": {
@@ -18383,9 +18383,9 @@
}
},
"ionicons": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.1.tgz",
"integrity": "sha512-1auVisfaXmkmxINer8Q3kJGHP1vSxk86hf7By95eJ+Av9+oBcNuAEBfSe3jaMaGRVxVw8U/2j23MFq7R3c0HPg==",
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.3.tgz",
"integrity": "sha512-L71djrMi8pAad66tpwdnO1vwcyluCFvehzxU1PpH1k/HpYBZhZ5IaYhqXipmqUvu5aEbd4cbRguYyI5Fd4bxTw==",
"requires": {
"@stencil/core": "^2.5.0"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "5.6.8",
"version": "5.8.3",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -32,7 +32,7 @@
],
"dependencies": {
"@stencil/core": "^2.4.0",
"ionicons": "^5.5.1",
"ionicons": "^5.5.3",
"tslib": "^2.1.0"
},
"devDependencies": {
@@ -41,7 +41,7 @@
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/sass": "1.3.2",
"@stencil/vue-output-target": "^0.4.2",
"@stencil/vue-output-target": "^0.4.3",
"@types/jest": "^26.0.20",
"@types/node": "^14.6.0",
"@types/puppeteer": "5.4.3",

View File

@@ -5,10 +5,12 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimeOptions, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, MenuChangeEventDetail, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerButton, PickerColumn, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, ViewController } from "./interface";
import { ActionSheetAttributes, ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimeOptions, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, LoadingAttributes, MenuChangeEventDetail, ModalAttributes, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerAttributes, PickerButton, PickerColumn, PopoverAttributes, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, ViewController } from "./interface";
import { IonicSafeString } from "./utils/sanitization";
import { AlertAttributes } from "./components/alert/alert-interface";
import { NavigationHookCallback } from "./components/route/route-interface";
import { SelectCompareFn } from "./components/select/select-interface";
import { ToastAttributes } from "./components/toast/toast-interface";
export namespace Components {
interface IonActionSheet {
/**
@@ -41,6 +43,10 @@ export namespace Components {
* Title for the action sheet.
*/
"header"?: string;
/**
* Additional attributes to pass to the action sheet.
*/
"htmlAttributes"?: ActionSheetAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -106,6 +112,10 @@ export namespace Components {
* The main title in the heading of the alert.
*/
"header"?: string;
/**
* Additional attributes to pass to the alert.
*/
"htmlAttributes"?: AlertAttributes;
/**
* Array of input to show in the alert.
*/
@@ -1177,6 +1187,10 @@ export namespace Components {
* Animation to use when the loading indicator is presented.
*/
"enterAnimation"?: AnimationBuilder;
/**
* Additional attributes to pass to the loader.
*/
"htmlAttributes"?: LoadingAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -1341,6 +1355,10 @@ export namespace Components {
* Animation to use when the modal is presented.
*/
"enterAnimation"?: AnimationBuilder;
/**
* Additional attributes to pass to the modal.
*/
"htmlAttributes"?: ModalAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -1558,6 +1576,10 @@ export namespace Components {
* @param name The name of the column.
*/
"getColumn": (name: string) => Promise<PickerColumn | undefined>;
/**
* Additional attributes to pass to the picker.
*/
"htmlAttributes"?: PickerAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -1630,6 +1652,10 @@ export namespace Components {
* The event to pass to the popover animation.
*/
"event": any;
/**
* Additional attributes to pass to the popover.
*/
"htmlAttributes"?: PopoverAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -1816,7 +1842,7 @@ export namespace Components {
*/
"pullMin": number;
/**
* Time it takes the refresher to to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
* Time it takes the refresher to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
*/
"snapbackDuration": string;
}
@@ -1910,7 +1936,7 @@ export namespace Components {
*/
"push": (url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise<boolean>;
/**
* By default `ion-router` will match the routes at the root path ("/"). That can be changed when
* The root path to use when matching URLs. By default, this is set to "/", but you can specify an alternate prefix for all URL paths.
*/
"root": string;
/**
@@ -2565,6 +2591,10 @@ export namespace Components {
* Header to be shown in the toast.
*/
"header"?: string;
/**
* Additional attributes to pass to the toast.
*/
"htmlAttributes"?: ToastAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -3346,6 +3376,10 @@ declare namespace LocalJSX {
* Title for the action sheet.
*/
"header"?: string;
/**
* Additional attributes to pass to the action sheet.
*/
"htmlAttributes"?: ActionSheetAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -3409,6 +3443,10 @@ declare namespace LocalJSX {
* The main title in the heading of the alert.
*/
"header"?: string;
/**
* Additional attributes to pass to the alert.
*/
"htmlAttributes"?: AlertAttributes;
/**
* Array of input to show in the alert.
*/
@@ -4520,6 +4558,10 @@ declare namespace LocalJSX {
* Animation to use when the loading indicator is presented.
*/
"enterAnimation"?: AnimationBuilder;
/**
* Additional attributes to pass to the loader.
*/
"htmlAttributes"?: LoadingAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -4678,6 +4720,10 @@ declare namespace LocalJSX {
* Animation to use when the modal is presented.
*/
"enterAnimation"?: AnimationBuilder;
/**
* Additional attributes to pass to the modal.
*/
"htmlAttributes"?: ModalAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -4812,6 +4858,10 @@ declare namespace LocalJSX {
* Animation to use when the picker is presented.
*/
"enterAnimation"?: AnimationBuilder;
/**
* Additional attributes to pass to the picker.
*/
"htmlAttributes"?: PickerAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -4886,6 +4936,10 @@ declare namespace LocalJSX {
* The event to pass to the popover animation.
*/
"event"?: any;
/**
* Additional attributes to pass to the popover.
*/
"htmlAttributes"?: PopoverAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
@@ -5106,7 +5160,7 @@ declare namespace LocalJSX {
*/
"pullMin"?: number;
/**
* Time it takes the refresher to to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
* Time it takes the refresher to snap back to the `refreshing` state. Does not apply when the refresher content uses a spinner, enabling the native refresher.
*/
"snapbackDuration"?: string;
}
@@ -5196,7 +5250,7 @@ declare namespace LocalJSX {
*/
"onIonRouteWillChange"?: (event: CustomEvent<RouterEventDetail>) => void;
/**
* By default `ion-router` will match the routes at the root path ("/"). That can be changed when
* The root path to use when matching URLs. By default, this is set to "/", but you can specify an alternate prefix for all URL paths.
*/
"root"?: string;
/**
@@ -5894,6 +5948,10 @@ declare namespace LocalJSX {
* Header to be shown in the toast.
*/
"header"?: string;
/**
* Additional attributes to pass to the toast.
*/
"htmlAttributes"?: ToastAttributes;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/

View File

@@ -1,3 +1,5 @@
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, Mode } from '../../interface';
export interface ActionSheetOptions {
@@ -11,11 +13,14 @@ export interface ActionSheetOptions {
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: ActionSheetAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface ActionSheetAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
export interface ActionSheetButton {
text?: string;
role?: 'cancel' | 'destructive' | 'selected' | string;

View File

@@ -110,10 +110,16 @@
text-align: $action-sheet-ios-text-align;
}
.action-sheet-title.action-sheet-has-sub-title {
font-weight: $action-sheet-ios-title-with-sub-title-font-weight;
}
.action-sheet-sub-title {
@include padding($action-sheet-ios-sub-title-padding-top, $action-sheet-ios-sub-title-padding-end, $action-sheet-ios-sub-title-padding-bottom, $action-sheet-ios-sub-title-padding-start);
font-size: $action-sheet-ios-sub-title-font-size;
font-weight: $action-sheet-ios-title-font-weight;
}

View File

@@ -55,6 +55,9 @@ $action-sheet-ios-title-font-size: 13px !default;
/// @prop - Font weight of the action sheet title
$action-sheet-ios-title-font-weight: 400 !default;
/// @prop - Font weight of the action sheet title when it has a sub title
$action-sheet-ios-title-with-sub-title-font-weight: 600 !default;
/// @prop - Border width of the action sheet title
$action-sheet-ios-title-border-width: $hairlines-width !default;
@@ -72,10 +75,10 @@ $action-sheet-ios-title-border-color: rgba($text-col
// --------------------------------------------------
/// @prop - Font size of the action sheet sub title
$action-sheet-ios-sub-title-font-size: 12px !default;
$action-sheet-ios-sub-title-font-size: 13px !default;
/// @prop - Padding top of the action sheet sub title
$action-sheet-ios-sub-title-padding-top: 15px !default;
$action-sheet-ios-sub-title-padding-top: 6px !default;
/// @prop - Padding end of the action sheet sub title
$action-sheet-ios-sub-title-padding-end: 0 !default;
@@ -103,7 +106,7 @@ $action-sheet-ios-button-text-color: ion-color(prim
$action-sheet-ios-button-icon-font-size: 28px !default;
/// @prop - Padding right of the action sheet button icon
$action-sheet-ios-button-icon-padding-right: .1em !default;
$action-sheet-ios-button-icon-padding-right: .3em !default;
/// @prop - Font size of the action sheet button
$action-sheet-ios-button-font-size: 20px !default;

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h, readTask } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { ActionSheetButton, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { ActionSheetAttributes, ActionSheetButton, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Gesture } from '../../utils/gesture';
import { createButtonActiveGesture } from '../../utils/gesture/button-active';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
@@ -90,6 +90,11 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* Additional attributes to pass to the action sheet.
*/
@Prop() htmlAttributes?: ActionSheetAttributes;
/**
* Emitted after the alert has presented.
*/
@@ -228,6 +233,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
}
render() {
const { htmlAttributes } = this;
const mode = getIonMode(this);
const allButtons = this.getButtons();
const cancelButton = allButtons.find(b => b.role === 'cancel');
@@ -238,6 +244,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
role="dialog"
aria-modal="true"
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${20000 + this.overlayIndex}`,
}}
@@ -258,7 +265,10 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
<div class="action-sheet-container">
<div class="action-sheet-group" ref={el => this.groupEl = el}>
{this.header !== undefined &&
<div class="action-sheet-title">
<div class={{
'action-sheet-title': true,
'action-sheet-has-sub-title': this.subHeader !== undefined
}}>
{this.header}
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
</div>

View File

@@ -34,6 +34,46 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### ActionSheetButton
```typescript
interface ActionSheetButton {
text?: string;
role?: 'cancel' | 'destructive' | 'selected' | string;
icon?: string;
cssClass?: string | string[];
handler?: () => boolean | void | Promise<boolean | void>;
}
```
### ActionSheetOptions
```typescript
interface ActionSheetOptions {
header?: string;
subHeader?: string;
cssClass?: string | string[];
buttons: (ActionSheetButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: ActionSheetAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### ActionSheetAttributes
```typescript
interface ActionSheetAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
<!-- Auto Generated Below -->
@@ -491,6 +531,7 @@ export default defineComponent({
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the action sheet is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `header` | `header` | Title for the action sheet. | `string \| undefined` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the action sheet. | `ActionSheetAttributes \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the action sheet is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |

View File

@@ -111,3 +111,21 @@ test('action-sheet:rtl: basic, scroll without cancel', async () => {
test('action-sheet:rtl: basic, custom backdrop', async () => {
await testActionSheet(DIRECTORY, '#customBackdrop', true);
});
// Attributes
test('action-sheet: htmlAttributes', async () => {
const page = await newE2EPage({ url: '/src/components/action-sheet/test/basic?ionic:_testing=true' });
await page.click('#basic');
await page.waitForSelector('#basic');
let toast = await page.find('ion-action-sheet');
expect(toast).not.toBe(null);
await toast.waitForVisible();
const attribute = await page.evaluate((el) => document.querySelector('ion-action-sheet').getAttribute('data-testid'));
expect(attribute).toEqual('basic-action-sheet');
});

View File

@@ -71,6 +71,9 @@
await openActionSheet({
header: "Albums",
subHeader: 'This is a sub header inside of an action sheet',
htmlAttributes: {
'data-testid': 'basic-action-sheet'
},
buttons: [{
text: 'Delete',
role: 'destructive',

View File

@@ -13,6 +13,7 @@ export interface AlertOptions {
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
htmlAttributes?: AlertAttributes;
mode?: Mode;
keyboardClose?: boolean;
@@ -22,6 +23,8 @@ export interface AlertOptions {
leaveAnimation?: AnimationBuilder;
}
export interface AlertAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
export interface AlertInput {
type?: TextFieldTypes | 'checkbox' | 'radio' | 'textarea';
name?: string;
@@ -44,7 +47,7 @@ export interface AlertInputAttributes extends JSXBase.InputHTMLAttributes<HTMLIn
export interface AlertButton {
text: string;
role?: string;
role?: 'cancel' | 'destructive' | string;
cssClass?: string | string[];
handler?: (value: any) => boolean | void | {[key: string]: any};
}

View File

@@ -80,7 +80,7 @@ $alert-md-message-empty-padding-bottom: $alert-md-message-empty-padding-to
$alert-md-message-empty-padding-start: $alert-md-message-empty-padding-end !default;
/// @prop - Maximum height of the alert content
$alert-md-content-max-height: 240px !default;
$alert-md-content-max-height: 266px !default;
/// @prop - Border width of the alert input
$alert-md-input-border-width: 1px !default;

View File

@@ -8,6 +8,7 @@ import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safe
import { IonicSafeString, sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
import { AlertAttributes } from './alert-interface';
import { iosEnterAnimation } from './animations/ios.enter';
import { iosLeaveAnimation } from './animations/ios.leave';
import { mdEnterAnimation } from './animations/md.enter';
@@ -110,6 +111,11 @@ export class Alert implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* Additional attributes to pass to the alert.
*/
@Prop() htmlAttributes?: AlertAttributes;
/**
* Emitted after the alert has presented.
*/
@@ -550,17 +556,19 @@ export class Alert implements ComponentInterface, OverlayInterface {
}
render() {
const { overlayIndex, header, subHeader } = this;
const { overlayIndex, header, subHeader, htmlAttributes } = this;
const mode = getIonMode(this);
const hdrId = `alert-${overlayIndex}-hdr`;
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
const msgId = `alert-${overlayIndex}-msg`;
const role = this.inputs.length > 0 || this.buttons.length > 0 ? 'alertdialog' : 'alert';
return (
<Host
role="dialog"
role={role}
aria-modal="true"
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${20000 + overlayIndex}`,
}}

View File

@@ -41,6 +41,82 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### AlertButton
```typescript
interface AlertButton {
text: string;
role?: 'cancel' | 'destructive' | string;
cssClass?: string | string[];
handler?: (value: any) => boolean | void | {[key: string]: any};
}
```
### AlertInput
```typescript
interface AlertInput {
type?: TextFieldTypes | 'checkbox' | 'radio' | 'textarea';
name?: string;
placeholder?: string;
value?: any;
label?: string;
checked?: boolean;
disabled?: boolean;
id?: string;
handler?: (input: AlertInput) => void;
min?: string | number;
max?: string | number;
cssClass?: string | string[];
attributes?: AlertInputAttributes | AlertTextareaAttributes;
tabindex?: number;
}
```
### AlertInputAttributes
```typescript
interface AlertInputAttributes extends JSXBase.InputHTMLAttributes<HTMLInputElement> {}
```
### AlertOptions
```typescript
interface AlertOptions {
header?: string;
subHeader?: string;
message?: string | IonicSafeString;
cssClass?: string | string[];
inputs?: AlertInput[];
buttons?: (AlertButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
htmlAttributes?: AlertAttributes;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### AlertAttributes
```typescript
interface AlertAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
### AlertTextareaAttributes
```typescript
interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement> {}
```
<!-- Auto Generated Below -->
@@ -1698,6 +1774,7 @@ export default defineComponent({
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the alert is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `header` | `header` | The main title in the heading of the alert. | `string \| undefined` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the alert. | `AlertAttributes \| undefined` | `undefined` |
| `inputs` | -- | Array of input to show in the alert. | `AlertInput[]` | `[]` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the alert is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |

View File

@@ -102,3 +102,21 @@ test(`alert:rtl: basic, radio`, async () => {
test(`alert:rtl: basic, checkbox`, async () => {
await testAlert(DIRECTORY, '#checkbox', true);
});
// Attributes
test('alert: htmlAttributes', async () => {
const page = await newE2EPage({ url: '/src/components/alert/test/basic?ionic:_testing=true' });
await page.click('#basic');
await page.waitForSelector('#basic');
let alert = await page.find('ion-alert');
expect(alert).not.toBe(null);
await alert.waitForVisible();
const attribute = await page.evaluate((el) => document.querySelector('ion-alert').getAttribute('data-testid'));
expect(attribute).toEqual('basic-alert');
});

View File

@@ -58,7 +58,10 @@
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['OK']
buttons: ['OK'],
htmlAttributes: {
'data-testid': 'basic-alert'
}
});
}

View File

@@ -92,6 +92,13 @@
font-kerning: none;
}
// Back Button Ripple effect
// --------------------------------------------------
ion-ripple-effect {
color: var(--ripple-color);
}
// Back Button with Color
// --------------------------------------------------
@@ -241,4 +248,4 @@ ion-icon {
:host(.in-toolbar:not(.in-toolbar-color)) {
color: #{var(--ion-toolbar-color, var(--color))};
}
}

View File

@@ -78,6 +78,8 @@
<ion-back-button color="secondary" class="custom"></ion-back-button>
<ion-back-button class="custom ion-focused"></ion-back-button>
<ion-back-button color="secondary" class="custom ion-focused"></ion-back-button>
<ion-back-button class="ripple"></ion-back-button>
<ion-back-button class="ripple" color="primary"></ion-back-button>
</p>
<ion-toolbar>
@@ -195,6 +197,10 @@
--ion-toolbar-background: #222;
--ion-toolbar-color: #ddd;
}
.ripple {
--ripple-color: red;
}
</style>
</body>

View File

@@ -129,30 +129,29 @@
// Material Design Button: Hover
// --------------------------------------------------
/**
* Only allow overriding of opacity here
* as developers should not be overriding
* colors when using the color prop.
*/
:host(.button-solid.ion-color.ion-focused) .button-native::after {
background: #{current-color(contrast)};
opacity: .24;
}
:host(.button-clear.ion-color.ion-focused) .button-native::after,
:host(.button-outline.ion-color.ion-focused) .button-native::after {
background: #{current-color(base)};
opacity: .12;
}
@media (any-hover: hover) {
:host(.button-solid.ion-color:hover) .button-native::after {
background: #{current-color(contrast)};
opacity: .08;
}
:host(.button-clear.ion-color:hover) .button-native::after,
:host(.button-outline.ion-color:hover) .button-native::after {
background: #{current-color(base)};
opacity: .04;
}
}

View File

@@ -62,7 +62,6 @@
user-select: none;
vertical-align: top; // the better option for most scenarios
vertical-align: -webkit-baseline-middle; // the best for those that support it
pointer-events: auto;
font-kerning: none;
}

View File

@@ -90,6 +90,7 @@
<ion-button fill="outline" class="ion-focused" color="dark">Dark.focused</ion-button>
<ion-button fill="outline" class="ion-activated ion-focused" color="dark">Dark.activated.focused</ion-button>
</p>
<p>
<ion-button fill="outline" disabled>Disabled</ion-button>
<ion-button fill="outline" color="secondary" disabled>Secondary Disabled</ion-button>

View File

@@ -89,6 +89,31 @@
<ion-button class="custom ion-activated" color="warning" fill="outline">Outline</ion-button>
<ion-button class="custom ion-activated" color="dark" fill="clear">Clear</ion-button>
</p>
<div class="custom-variables">
<ion-button>Button</ion-button>
<ion-button fill="clear">Button</ion-button>
<ion-button fill="outline">Button</ion-button>
<br>
<ion-button class="ion-focused">Button</ion-button>
<ion-button class="ion-focused" fill="clear">Button</ion-button>
<ion-button class="ion-focused" fill="outline">Button</ion-button>
<br>
<ion-button color="tertiary">Button</ion-button>
<ion-button color="tertiary" fill="clear">Button</ion-button>
<ion-button color="tertiary" fill="outline">Button</ion-button>
<br>
<ion-button color="tertiary" class="ion-focused">Button</ion-button>
<ion-button color="tertiary" class="ion-focused" fill="clear">Button</ion-button>
<ion-button color="tertiary" class="ion-focused" fill="outline">Button</ion-button>
</div>
</ion-content>
</ion-app>
@@ -110,6 +135,17 @@
.custom {
--color: red;
}
.custom-variables ion-button {
--color: black;
--background: pink;
--background-focused: red;
--background-hover: green;
--background-focused-opacity: .5;
--background-hover-opacity: .5;
}
</style>
</body>
</html>

View File

@@ -250,12 +250,12 @@ export class CardExample {
</template>
<script>
import { IonCard, IonCardContent, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel } from '@ionic/vue';
import { IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel } from '@ionic/vue';
import { pin, walk, warning, wifi, wine } from 'ionicons/icons';
import { defineComponent } from 'vue';
export default defineComponent({
components: { IonCard, IonCardContent, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel }
components: { IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel }
setup() {
return { warning };
}

View File

@@ -49,12 +49,12 @@
</template>
<script>
import { IonCard, IonCardContent, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel } from '@ionic/vue';
import { IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel } from '@ionic/vue';
import { pin, walk, warning, wifi, wine } from 'ionicons/icons';
import { defineComponent } from 'vue';
export default defineComponent({
components: { IonCard, IonCardContent, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel }
components: { IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonIcon, IonItem, IonLabel }
setup() {
return { warning };
}

View File

@@ -1,5 +1,5 @@
export interface CheckboxChangeEventDetail {
value: any;
export interface CheckboxChangeEventDetail<T = any> {
value: T;
checked: boolean;
}

View File

@@ -271,11 +271,11 @@ export default defineComponent({
## Events
| Event | Description | Type |
| ----------- | ---------------------------------------------- | ---------------------------------------- |
| `ionBlur` | Emitted when the checkbox loses focus. | `CustomEvent<void>` |
| `ionChange` | Emitted when the checked property has changed. | `CustomEvent<CheckboxChangeEventDetail>` |
| `ionFocus` | Emitted when the checkbox has focus. | `CustomEvent<void>` |
| Event | Description | Type |
| ----------- | ---------------------------------------------- | --------------------------------------------- |
| `ionBlur` | Emitted when the checkbox loses focus. | `CustomEvent<void>` |
| `ionChange` | Emitted when the checked property has changed. | `CustomEvent<CheckboxChangeEventDetail<any>>` |
| `ionFocus` | Emitted when the checkbox has focus. | `CustomEvent<void>` |
## Shadow Parts

View File

@@ -150,9 +150,9 @@
display: none;
position: absolute;
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
left: -100%;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
width: 100%;
height: 100vh;
@@ -165,9 +165,9 @@
.transition-cover {
position: absolute;
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
right: 0;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
width: 100%;
height: 100%;
@@ -181,9 +181,9 @@
display: block;
position: absolute;
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
right: 0;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
width: 10px;
height: 100%;

View File

@@ -792,31 +792,31 @@ export default defineComponent({
## Properties
| Property | Attribute | Description | Type | Default |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| `cancelText` | `cancel-text` | The text to display on the picker's cancel button. | `string` | `'Cancel'` |
| `dayNames` | `day-names` | Full day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `dayShortNames` | `day-short-names` | Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']` | `string \| string[] \| undefined` | `undefined` |
| `dayValues` | `day-values` | Values used to create the list of selectable days. By default every day is shown for the given month. However, to control exactly which days of the month to display, the `dayValues` input can take a number, an array of numbers, or a string of comma separated numbers. Note that even if the array days have an invalid number for the selected month, like `31` in February, it will correctly not show days which are not valid for the selected month. | `number \| number[] \| string \| undefined` | `undefined` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the datetime. | `boolean` | `false` |
| `displayFormat` | `display-format` | The display format of the date and time as text that shows within the item. When the `pickerFormat` input is not used, then the `displayFormat` is used for both display the formatted text, and determining the datetime picker's columns. See the `pickerFormat` input description for more info. Defaults to `MMM D, YYYY`. | `string` | `'MMM D, YYYY'` |
| `displayTimezone` | `display-timezone` | The timezone to use for display purposes only. See [Date.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString) for a list of supported timezones. If no value is provided, the component will default to displaying times in the user's local timezone. | `string \| undefined` | `undefined` |
| `doneText` | `done-text` | The text to display on the picker's "Done" button. | `string` | `'Done'` |
| `hourValues` | `hour-values` | Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers. | `number \| number[] \| string \| undefined` | `undefined` |
| `max` | `max` | The maximum datetime allowed. Value must be a date string following the [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime), `1996-12-19`. The format does not have to be specific to an exact datetime. For example, the maximum could just be the year, such as `1994`. Defaults to the end of this year. | `string \| undefined` | `undefined` |
| `min` | `min` | The minimum datetime allowed. Value must be a date string following the [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime), such as `1996-12-19`. The format does not have to be specific to an exact datetime. For example, the minimum could just be the year, such as `1994`. Defaults to the beginning of the year, 100 years ago from today. | `string \| undefined` | `undefined` |
| `minuteValues` | `minute-values` | Values used to create the list of selectable minutes. By default the minutes range from `0` to `59`. However, to control exactly which minutes to display, the `minuteValues` input can take a number, an array of numbers, or a string of comma separated numbers. For example, if the minute selections should only be every 15 minutes, then this input value would be `minuteValues="0,15,30,45"`. | `number \| number[] \| string \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `monthNames` | `month-names` | Full names for each month name. This can be used to provide locale month names. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `monthShortNames` | `month-short-names` | Short abbreviated names for each month name. This can be used to provide locale month names. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `monthValues` | `month-values` | Values used to create the list of selectable months. By default the month values range from `1` to `12`. However, to control exactly which months to display, the `monthValues` input can take a number, an array of numbers, or a string of comma separated numbers. For example, if only summer months should be shown, then this input value would be `monthValues="6,7,8"`. Note that month numbers do *not* have a zero-based index, meaning January's value is `1`, and December's is `12`. | `number \| number[] \| string \| undefined` | `undefined` |
| `name` | `name` | The name of the control, which is submitted with the form data. | `string` | `this.inputId` |
| `pickerFormat` | `picker-format` | The format of the date and time picker columns the user selects. A datetime input can have one or many datetime parts, each getting their own column which allow individual selection of that particular datetime part. For example, year and month columns are two individually selectable columns which help choose an exact date from the datetime picker. Each column follows the string parse format. Defaults to use `displayFormat`. | `string \| undefined` | `undefined` |
| `pickerOptions` | -- | Any additional options that the picker interface can accept. See the [Picker API docs](../picker) for the picker options. | `undefined \| { columns?: PickerColumn[] \| undefined; buttons?: PickerButton[] \| undefined; cssClass?: string \| string[] \| undefined; showBackdrop?: boolean \| undefined; backdropDismiss?: boolean \| undefined; animated?: boolean \| undefined; mode?: Mode \| undefined; keyboardClose?: boolean \| undefined; id?: string \| undefined; enterAnimation?: AnimationBuilder \| undefined; leaveAnimation?: AnimationBuilder \| undefined; }` | `undefined` |
| `placeholder` | `placeholder` | The text to display when there's no date selected yet. Using lowercase to match the input attribute | `null \| string \| undefined` | `undefined` |
| `readonly` | `readonly` | If `true`, the datetime appears normal but is not interactive. | `boolean` | `false` |
| `value` | `value` | The value of the datetime as a valid ISO 8601 datetime string. | `null \| string \| undefined` | `undefined` |
| `yearValues` | `year-values` | Values used to create the list of selectable years. By default the year values range between the `min` and `max` datetime inputs. However, to control exactly which years to display, the `yearValues` input can take a number, an array of numbers, or string of comma separated numbers. For example, to show upcoming and recent leap years, then this input's value would be `yearValues="2024,2020,2016,2012,2008"`. | `number \| number[] \| string \| undefined` | `undefined` |
| Property | Attribute | Description | Type | Default |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| `cancelText` | `cancel-text` | The text to display on the picker's cancel button. | `string` | `'Cancel'` |
| `dayNames` | `day-names` | Full day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `dayShortNames` | `day-short-names` | Short abbreviated day of the week names. This can be used to provide locale names for each day in the week. Defaults to English. Defaults to: `['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']` | `string \| string[] \| undefined` | `undefined` |
| `dayValues` | `day-values` | Values used to create the list of selectable days. By default every day is shown for the given month. However, to control exactly which days of the month to display, the `dayValues` input can take a number, an array of numbers, or a string of comma separated numbers. Note that even if the array days have an invalid number for the selected month, like `31` in February, it will correctly not show days which are not valid for the selected month. | `number \| number[] \| string \| undefined` | `undefined` |
| `disabled` | `disabled` | If `true`, the user cannot interact with the datetime. | `boolean` | `false` |
| `displayFormat` | `display-format` | The display format of the date and time as text that shows within the item. When the `pickerFormat` input is not used, then the `displayFormat` is used for both display the formatted text, and determining the datetime picker's columns. See the `pickerFormat` input description for more info. Defaults to `MMM D, YYYY`. | `string` | `'MMM D, YYYY'` |
| `displayTimezone` | `display-timezone` | The timezone to use for display purposes only. See [Date.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString) for a list of supported timezones. If no value is provided, the component will default to displaying times in the user's local timezone. | `string \| undefined` | `undefined` |
| `doneText` | `done-text` | The text to display on the picker's "Done" button. | `string` | `'Done'` |
| `hourValues` | `hour-values` | Values used to create the list of selectable hours. By default the hour values range from `0` to `23` for 24-hour, or `1` to `12` for 12-hour. However, to control exactly which hours to display, the `hourValues` input can take a number, an array of numbers, or a string of comma separated numbers. | `number \| number[] \| string \| undefined` | `undefined` |
| `max` | `max` | The maximum datetime allowed. Value must be a date string following the [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime), `1996-12-19`. The format does not have to be specific to an exact datetime. For example, the maximum could just be the year, such as `1994`. Defaults to the end of this year. | `string \| undefined` | `undefined` |
| `min` | `min` | The minimum datetime allowed. Value must be a date string following the [ISO 8601 datetime format standard](https://www.w3.org/TR/NOTE-datetime), such as `1996-12-19`. The format does not have to be specific to an exact datetime. For example, the minimum could just be the year, such as `1994`. Defaults to the beginning of the year, 100 years ago from today. | `string \| undefined` | `undefined` |
| `minuteValues` | `minute-values` | Values used to create the list of selectable minutes. By default the minutes range from `0` to `59`. However, to control exactly which minutes to display, the `minuteValues` input can take a number, an array of numbers, or a string of comma separated numbers. For example, if the minute selections should only be every 15 minutes, then this input value would be `minuteValues="0,15,30,45"`. | `number \| number[] \| string \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
| `monthNames` | `month-names` | Full names for each month name. This can be used to provide locale month names. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `monthShortNames` | `month-short-names` | Short abbreviated names for each month name. This can be used to provide locale month names. Defaults to English. | `string \| string[] \| undefined` | `undefined` |
| `monthValues` | `month-values` | Values used to create the list of selectable months. By default the month values range from `1` to `12`. However, to control exactly which months to display, the `monthValues` input can take a number, an array of numbers, or a string of comma separated numbers. For example, if only summer months should be shown, then this input value would be `monthValues="6,7,8"`. Note that month numbers do *not* have a zero-based index, meaning January's value is `1`, and December's is `12`. | `number \| number[] \| string \| undefined` | `undefined` |
| `name` | `name` | The name of the control, which is submitted with the form data. | `string` | `this.inputId` |
| `pickerFormat` | `picker-format` | The format of the date and time picker columns the user selects. A datetime input can have one or many datetime parts, each getting their own column which allow individual selection of that particular datetime part. For example, year and month columns are two individually selectable columns which help choose an exact date from the datetime picker. Each column follows the string parse format. Defaults to use `displayFormat`. | `string \| undefined` | `undefined` |
| `pickerOptions` | -- | Any additional options that the picker interface can accept. See the [Picker API docs](../picker) for the picker options. | `undefined \| { columns?: PickerColumn[] \| undefined; buttons?: PickerButton[] \| undefined; cssClass?: string \| string[] \| undefined; showBackdrop?: boolean \| undefined; backdropDismiss?: boolean \| undefined; animated?: boolean \| undefined; mode?: Mode \| undefined; keyboardClose?: boolean \| undefined; id?: string \| undefined; htmlAttributes?: PickerAttributes \| undefined; enterAnimation?: AnimationBuilder \| undefined; leaveAnimation?: AnimationBuilder \| undefined; }` | `undefined` |
| `placeholder` | `placeholder` | The text to display when there's no date selected yet. Using lowercase to match the input attribute | `null \| string \| undefined` | `undefined` |
| `readonly` | `readonly` | If `true`, the datetime appears normal but is not interactive. | `boolean` | `false` |
| `value` | `value` | The value of the datetime as a valid ISO 8601 datetime string. | `null \| string \| undefined` | `undefined` |
| `yearValues` | `year-values` | Values used to create the list of selectable years. By default the year values range between the `min` and `max` datetime inputs. However, to control exactly which years to display, the `yearValues` input can take a number, an array of numbers, or string of comma separated numbers. For example, to show upcoming and recent leap years, then this input's value would be `yearValues="2024,2020,2016,2012,2008"`. | `number \| number[] \| string \| undefined` | `undefined` |
## Events

View File

@@ -1,8 +1,10 @@
import { Component, ComponentInterface, Element, Host, Prop, h, writeTask } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { inheritAttributes } from '../../utils/helpers';
import { cloneElement, createHeaderIndex, handleContentScroll, handleToolbarIntersection, setHeaderActive, setToolbarBackgroundOpacity } from './header.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
@@ -20,6 +22,7 @@ export class Header implements ComponentInterface {
private contentScrollCallback?: any;
private intersectionObserver?: any;
private collapsibleMainHeader?: HTMLElement;
private inheritedAttributes: { [k: string]: any } = {};
@Element() el!: HTMLElement;
@@ -41,6 +44,10 @@ export class Header implements ComponentInterface {
*/
@Prop() translucent = false;
componentWillLoad() {
this.inheritedAttributes = inheritAttributes(this.el, ['role']);
}
async componentDidLoad() {
await this.checkCollapsibleHeader();
}
@@ -143,9 +150,10 @@ export class Header implements ComponentInterface {
}
render() {
const { translucent } = this;
const { translucent, inheritedAttributes } = this;
const mode = getIonMode(this);
const collapse = this.collapse || 'none';
return (
<Host
role="banner"
@@ -159,6 +167,7 @@ export class Header implements ComponentInterface {
[`header-collapse-${collapse}`]: true,
[`header-translucent-${mode}`]: this.translucent,
}}
{...inheritedAttributes}
>
{ mode === 'ios' && translucent &&
<div class="header-background"></div>

View File

@@ -0,0 +1,11 @@
import { newE2EPage } from '@stencil/core/testing';
import { AxePuppeteer } from '@axe-core/puppeteer';
test('header: axe', async () => {
const page = await newE2EPage({
url: '/src/components/header/test/a11y?ionic:_testing=true'
});
const results = await new AxePuppeteer(page).analyze();
expect(results.violations.length).toEqual(0);
});

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Header - a11y</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link href="../../../../../css/core.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-header></ion-header>
<main>
<h1>Headers</h1>
<ion-header role="none"></ion-header>
</main>
</body>
</html>

View File

@@ -60,10 +60,12 @@ export class Img implements ComponentInterface {
'isIntersecting' in window.IntersectionObserverEntry.prototype) {
this.removeIO();
this.io = new IntersectionObserver(data => {
// because there will only ever be one instance
// of the element we are observing
// we can just use data[0]
if (data[0].isIntersecting) {
/**
* On slower devices, it is possible for an intersection observer entry to contain multiple
* objects in the array. This happens when quickly scrolling an image into view and then out of
* view. In this case, the last object represents the current state of the component.
*/
if (data[data.length - 1].isIntersecting) {
this.load();
this.removeIO();
}

View File

@@ -104,7 +104,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
[mode]: true,
'item-option-disabled': disabled,
'item-option-expandable': expandable,
'ion-activatable': true,
'ion-activatable': true
})}
>
<TagType

View File

@@ -5,10 +5,10 @@
ion-item-options {
@include multi-dir() {
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
top: 0;
right: 0;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
}
@include ltr() {
@@ -19,10 +19,10 @@ ion-item-options {
justify-content: flex-start;
&:not(.item-options-end) {
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
right: auto;
left: 0;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
justify-content: flex-end;
}
@@ -41,10 +41,10 @@ ion-item-options {
.item-options-start {
@include multi-dir() {
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
right: auto;
left: 0;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
}
@include ltr() {

View File

@@ -32,7 +32,7 @@ ion-item-sliding .item {
.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
@include multi-dir() {
/* stylelint-disable-next-line property-blacklist */
/* stylelint-disable-next-line property-disallowed-list */
padding-left: 100%;
}
@@ -50,7 +50,7 @@ ion-item-sliding .item {
.item-sliding-active-swipe-start .item-options-start .item-option-expandable {
@include multi-dir() {
/* stylelint-disable-next-line property-blacklist */
/* stylelint-disable-next-line property-disallowed-list */
padding-right: 100%;
}

View File

@@ -43,6 +43,8 @@ export class ItemSliding implements ComponentInterface {
private rightOptions?: HTMLIonItemOptionsElement;
private optsDirty = true;
private gesture?: Gesture;
private closestContent: HTMLIonContentElement | null = null;
private initialContentScrollY = true;
@Element() el!: HTMLIonItemSlidingElement;
@@ -66,6 +68,8 @@ export class ItemSliding implements ComponentInterface {
async connectedCallback() {
this.item = this.el.querySelector('ion-item');
this.closestContent = this.el.closest('ion-content');
await this.updateOptions();
this.gesture = (await import('../../utils/gesture')).createGesture({
@@ -247,13 +251,35 @@ export class ItemSliding implements ComponentInterface {
const selected = openSlidingItem;
if (selected && selected !== this.el) {
this.closeOpened();
return false;
}
return !!(this.rightOptions || this.leftOptions);
}
private disableContentScrollY() {
if (this.closestContent === null) { return }
this.initialContentScrollY = this.closestContent.scrollY;
this.closestContent.scrollY = false;
}
private restoreContentScrollY() {
if (this.closestContent === null) { return }
this.closestContent.scrollY = this.initialContentScrollY;
}
private onStart() {
/**
* We need to query for the ion-item
* every time the gesture starts. Developers
* may toggle ion-item elements via *ngIf.
*/
this.item = this.el.querySelector('ion-item');
// Prevent scrolling during gesture
this.disableContentScrollY();
openSlidingItem = this.el;
if (this.tmr !== undefined) {
@@ -298,6 +324,9 @@ export class ItemSliding implements ComponentInterface {
}
private onEnd(gesture: GestureDetail) {
// Restore ion-content scrollY to initial value when gesture ends
this.restoreContentScrollY();
const velocity = gesture.velocityX;
let restingPoint = (this.openAmount > 0)
@@ -365,16 +394,28 @@ export class ItemSliding implements ComponentInterface {
? SlidingState.Start | SlidingState.SwipeStart
: SlidingState.Start;
} else {
/**
* Item sliding cannot be interrupted
* while closing the item. If it did,
* it would allow the item to get into an
* inconsistent state where multiple
* items are then open at the same time.
*/
if (this.gesture) {
this.gesture.enable(false);
}
this.tmr = setTimeout(() => {
this.state = SlidingState.Disabled;
this.tmr = undefined;
if (this.gesture) {
this.gesture.enable(true);
}
}, 600) as any;
openSlidingItem = undefined;
style.transform = '';
return;
}
style.transform = `translate3d(${-openAmount}px,0,0)`;
this.ionDrag.emit({
amount: openAmount,

View File

@@ -41,6 +41,7 @@
<ion-button expand="block" onclick="openItem('start')">Open Item Start</ion-button>
<ion-button expand="block" onclick="openItem('end')">Open Item End</ion-button>
<ion-button expand="block" onclick="openItemOneSide()">Open Item with only one side</ion-button>
<ion-button expand="block" onclick="setDynaicItem()">Swap dynamic item</ion-button>
</div>
<ion-list id="list">
@@ -369,6 +370,17 @@
</ion-item-options>
</ion-item-sliding>
<ion-item-sliding id="dynamic-item">
<ion-item>
<ion-label>Dynamic First Item</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option color="tertiary" expandable>
First Item Options
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
<ion-item>
<ion-label class="ion-text-wrap">
<h2>Normal ion-item (no sliding)</h2>
@@ -387,6 +399,20 @@
</ion-list>
<script>
const setDynaicItem = () => {
const sliding = document.querySelector('#dynamic-item');
sliding.innerHTML = `
<ion-item>
<ion-label>Dynamic Second Item</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option color="tertiary" expandable>
Second Item Options
</ion-item-option>
</ion-item-options>
`
}
var dynamicSlidingEnabled = document.getElementsByClassName('sliding-enabled');
// Toggle the dynamic options

View File

@@ -308,7 +308,7 @@ button, a {
z-index: 1;
}
::slotted(ion-label) {
::slotted(ion-label:not([slot="end"])) {
flex: 1;
}

View File

@@ -173,7 +173,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
}
componentDidLoad() {
this.setMultipleInputs();
raf(() => this.setMultipleInputs());
}
// If the item contains multiple clickable elements and/or inputs, then the item
@@ -251,7 +251,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
render() {
const { detail, detailIcon, download, labelColorStyles, lines, disabled, href, rel, target, routerAnimation, routerDirection } = this;
const childStyles = {};
const childStyles = {} as any;
const mode = getIonMode(this);
const clickable = this.isClickable();
const canActivate = this.canActivate();
@@ -273,10 +273,11 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
this.itemStyles.forEach(value => {
Object.assign(childStyles, value);
});
const ariaDisabled = (disabled || childStyles['item-interactive-disabled']) ? 'true' : null;
return (
<Host
aria-disabled={disabled ? 'true' : null}
aria-disabled={ariaDisabled}
class={{
...childStyles,
...labelColorStyles,

View File

@@ -0,0 +1,11 @@
import { newE2EPage } from '@stencil/core/testing';
import { AxePuppeteer } from '@axe-core/puppeteer';
test('item: axe', async () => {
const page = await newE2EPage({
url: '/src/components/item/test/a11y?ionic:_testing=true'
});
const results = await new AxePuppeteer(page).analyze();
expect(results.violations.length).toEqual(0);
});

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Item - a11y</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link href="../../../../../css/core.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<main>
<h1>Item</h1>
<ion-item>
<ion-label>Item with Input</ion-label>
<ion-input placeholder="Placeholder"></ion-input>
</ion-item>
<ion-item disabled>
<ion-label>Item disabled with Input</ion-label>
<ion-input placeholder="Placeholder"></ion-input>
</ion-item>
<ion-item>
<ion-label>Item with Input disabled</ion-label>
<ion-input placeholder="Placeholder" disabled></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Item with Select</ion-label>
<ion-select>
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item disabled>
<ion-label position="floating">Item disabled with Select</ion-label>
<ion-select>
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label position="floating">Item with Select disabled</ion-label>
<ion-select disabled>
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Item with Toggle</ion-label>
<ion-toggle slot="end"></ion-toggle>
</ion-item>
<ion-item disabled>
<ion-label>Item disabled with Toggle</ion-label>
<ion-toggle slot="end"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Item with Toggle disabled</ion-label>
<ion-toggle slot="end" disabled></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Item with Radio</ion-label>
<ion-radio slot="start" value="biff"></ion-radio>
</ion-item>
<ion-item disabled>
<ion-label>Item disabled with Radio</ion-label>
<ion-radio slot="start" value="biff"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Item with Radio disabled</ion-label>
<ion-radio slot="start" value="biff" disabled></ion-radio>
</ion-item>
</main>
</body>
</html>

View File

@@ -118,6 +118,25 @@
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>End Labels</ion-list-header>
<ion-item>
<ion-label slot="end">Time</ion-label>
<ion-datetime display-format="DDDD MMMM D YYYY hh:mm:ss a" value="2019-10-01T15:43:40.394Z"></ion-datetime>
</ion-item>
<ion-item>
<ion-label slot="end">From</ion-label>
<ion-input placeholder="Choose Starting Point"></ion-input>
</ion-item>
<ion-item>
<ion-label slot="end">Destination</ion-label>
<ion-select placeholder="Choose Really Really Long Destination Here">
<ion-select-option>Madison, WI</ion-select-option>
<ion-select-option>Atlanta, GA</ion-select-option>
</ion-select>
</ion-item>
</ion-list>
</ion-content>
</ion-app>

View File

@@ -89,11 +89,10 @@
color: #{$item-ios-paragraph-text-color};
}
:host-context(.ion-color)::slotted(p) {
:host(.in-item-color)::slotted(p) {
color: inherit;
}
::slotted(*) h2:last-child,
::slotted(*) h3:last-child,
::slotted(*) h4:last-child,

View File

@@ -104,6 +104,6 @@
color: $item-md-paragraph-text-color;
}
:host-context(.ion-color)::slotted(p) {
:host(.in-item-color)::slotted(p) {
color: inherit;
}

View File

@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop
import { getIonMode } from '../../global/ionic-global';
import { Color, StyleEventDetail } from '../../interface';
import { createColorClasses } from '../../utils/theme';
import { createColorClasses, hostContext } from '../../utils/theme';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
@@ -101,6 +101,7 @@ export class Label implements ComponentInterface {
<Host
class={createColorClasses(this.color, {
[mode]: true,
'in-item-color': hostContext('ion-item.ion-color', this.el),
[`label-${position}`]: position !== undefined,
[`label-no-animate`]: (this.noAnimate)
})}

View File

@@ -0,0 +1,10 @@
import { newE2EPage } from '@stencil/core/testing';
test('label: color', async () => {
const page = await newE2EPage({
url: '/src/components/label/test/color?ionic:_testing=true'
});
const compare = await page.compareScreenshot();
expect(compare).toMatchScreenshot();
});

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Label - Color</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Label - Color</ion-title>
</ion-toolbar>
</ion-header>
<ion-content color="light">
<ion-item>
<ion-label>Label Text<p>This paragraph should not inherit the color from content</p></ion-label>
</ion-item>
</ion-content>
</ion-app>
</body>
</html>

View File

@@ -1,3 +1,5 @@
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, Mode, SpinnerTypes } from '../../interface';
import { IonicSafeString } from '../../utils/sanitization';
@@ -13,7 +15,10 @@ export interface LoadingOptions {
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: LoadingAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface LoadingAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}

View File

@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Meth
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, OverlayEventDetail, OverlayInterface, SpinnerTypes } from '../../interface';
import { AnimationBuilder, LoadingAttributes, OverlayEventDetail, OverlayInterface, SpinnerTypes } from '../../interface';
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { IonicSafeString, sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
@@ -92,6 +92,11 @@ export class Loading implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* Additional attributes to pass to the loader.
*/
@Prop() htmlAttributes?: LoadingAttributes;
/**
* Emitted after the loading has presented.
*/
@@ -179,15 +184,16 @@ export class Loading implements ComponentInterface, OverlayInterface {
}
render() {
const { message, spinner } = this;
const { message, spinner, htmlAttributes } = this;
const mode = getIonMode(this);
return (
<Host
onIonBackdropTap={this.onBackdropTap}
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${40000 + this.overlayIndex}`
}}
onIonBackdropTap={this.onBackdropTap}
class={{
...getClassMap(this.cssClass),
[mode]: true,

View File

@@ -37,6 +37,35 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### LoadingOptions
```typescript
interface LoadingOptions {
spinner?: SpinnerTypes | null;
message?: string | IonicSafeString;
cssClass?: string | string[];
showBackdrop?: boolean;
duration?: number;
translucent?: boolean;
animated?: boolean;
backdropDismiss?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: LoadingAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### LoadingAttributes
```typescript
interface LoadingAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
<!-- Auto Generated Below -->
@@ -139,17 +168,23 @@ import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
interface LoadingProps {}
const LoadingExample: React.FC<LoadingProps> = () => {
const [present] = useIonLoading();
const [present, dismiss] = useIonLoading();
/**
* The recommended way of dismissing is to use the `dismiss` property
* on `IonLoading`, but the `dismiss` method returned from `useIonLoading`
* can be used for more complex scenarios.
*/
return (
<IonPage>
<IonContent>
<IonButton
expand="block"
onClick={() =>
onClick={() => {
present({
duration: 3000,
message: 'Loading...',
duration: 3000
})
}
}}
>
Show Loading
</IonButton>
@@ -347,6 +382,7 @@ export default defineComponent({
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `duration` | `duration` | Number of milliseconds to wait before dismissing the loading indicator. | `number` | `0` |
| `enterAnimation` | -- | Animation to use when the loading indicator is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the loader. | `LoadingAttributes \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the loading indicator is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `message` | `message` | Optional text content to display in the loading indicator. | `IonicSafeString \| string \| undefined` | `undefined` |

View File

@@ -95,3 +95,19 @@ test('loading:rtl: backdrop standalone', async () => {
test('loading:rtl: html content basic', async () => {
await testLoading(DIRECTORY, '#html-content-loading', true);
});
test('loading: htmlAttributes', async () => {
const page = await newE2EPage({ url: '/src/components/loading/test/basic?ionic:_testing=true' });
await page.click('#basic-loading');
await page.waitForSelector('#basic-loading');
let alert = await page.find('ion-loading');
expect(alert).not.toBe(null);
await alert.waitForVisible();
const attribute = await page.evaluate((el) => document.querySelector('ion-loading').getAttribute('data-testid'));
expect(attribute).toEqual('basic-loading');
});

View File

@@ -24,7 +24,7 @@
</ion-header>
<ion-content class="ion-padding">
<ion-button id="basic-loading" expand="block" onclick="openLoading({ message: 'Hellooo', duration: 2000 })">Show Loading</ion-button>
<ion-button id="basic-loading" expand="block" onclick="openLoading({ message: 'Hellooo', duration: 2000, htmlAttributes: { 'data-testid': 'basic-loading' } })">Show Loading</ion-button>
<ion-button id="default" expand="block" onclick="openLoading({duration: 2000, content: 'Please wait...'})">Show Default Loading</ion-button>
<ion-button id="long-content-loading" expand="block" onclick="openLoading({duration: 2000, message: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea voluptatibus quibusdam eum nihil optio, ullam accusamus magni, nobis suscipit reprehenderit, sequi quam amet impedit. Accusamus dolorem voluptates laborum dolor obcaecati.'})">Show Loading with long message</ion-button>
<ion-button id="no-spinner-loading" expand="block" onclick="openLoading({duration: 2000, message: 'Please wait...', spinner: null})">Show Loading with no spinner</ion-button>

View File

@@ -7,17 +7,23 @@ import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
interface LoadingProps {}
const LoadingExample: React.FC<LoadingProps> = () => {
const [present] = useIonLoading();
const [present, dismiss] = useIonLoading();
/**
* The recommended way of dismissing is to use the `dismiss` property
* on `IonLoading`, but the `dismiss` method returned from `useIonLoading`
* can be used for more complex scenarios.
*/
return (
<IonPage>
<IonContent>
<IonButton
expand="block"
onClick={() =>
onClick={() => {
present({
duration: 3000,
message: 'Loading...',
duration: 3000
})
}
}}
>
Show Loading
</IonButton>

View File

@@ -4,6 +4,7 @@ import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { Color } from '../../interface';
import { ButtonInterface } from '../../utils/element-interface';
import { inheritAttributes } from '../../utils/helpers';
import { menuController } from '../../utils/menu-controller';
import { createColorClasses, hostContext } from '../../utils/theme';
import { updateVisibility } from '../menu-toggle/menu-toggle-util';
@@ -23,6 +24,8 @@ import { updateVisibility } from '../menu-toggle/menu-toggle-util';
shadow: true
})
export class MenuButton implements ComponentInterface, ButtonInterface {
private inheritedAttributes: { [k: string]: any } = {};
@Element() el!: HTMLIonSegmentElement;
@State() visible = false;
@@ -54,6 +57,10 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
*/
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
componentWillLoad() {
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
}
componentDidLoad() {
this.visibilityChanged();
}
@@ -69,7 +76,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
}
render() {
const { color, disabled } = this;
const { color, disabled, inheritedAttributes } = this;
const mode = getIonMode(this);
const menuIcon = config.get('menuIcon', mode === 'ios' ? 'menu-outline' : 'menu-sharp');
const hidden = this.autoHide && !this.visible;
@@ -78,6 +85,8 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
type: this.type
};
const ariaLabel = inheritedAttributes['aria-label'] || 'menu';
return (
<Host
onClick={this.onClick}
@@ -99,7 +108,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
disabled={disabled}
class="button-native"
part="native"
aria-label="menu"
aria-label={ariaLabel}
>
<span class="button-inner">
<slot>

View File

@@ -0,0 +1,11 @@
import { newE2EPage } from '@stencil/core/testing';
import { AxePuppeteer } from '@axe-core/puppeteer';
test('menu-button: axe', async () => {
const page = await newE2EPage({
url: '/src/components/menu-button/test/a11y?ionic:_testing=true'
});
const results = await new AxePuppeteer(page).analyze();
expect(results.violations.length).toEqual(0);
});

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Menu Button - a11y</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link href="../../../../../css/core.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
<script src="../../../../../scripts/testing/scripts.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<main>
<h1>Menu Button</h1>
<ion-menu-button auto-hide="false"></ion-menu-button>
<ion-menu-button auto-hide="false" aria-label="Custom Label"></ion-menu-button>
</main>
</body>
</html>

View File

@@ -29,6 +29,7 @@
<ion-menu-button auto-hide="false" color="secondary" class="custom ion-focused"></ion-menu-button>
<ion-menu-button auto-hide="false" class="custom-large"></ion-menu-button>
<ion-menu-button auto-hide="false" class="custom-large ion-focused"></ion-menu-button>
<ion-menu-button auto-hide="false" aria-label="My Custom Menu Button Label"></ion-menu-button>
<h1>Colors</h1>
<ion-menu-button auto-hide="false" color="primary"></ion-menu-button>

View File

@@ -63,7 +63,7 @@
--ion-safe-area-right: 0px;
@include multi-dir() {
/* stylelint-disable property-blacklist */
/* stylelint-disable property-disallowed-list */
right: auto;
left: 0;
}
@@ -75,7 +75,7 @@
@include multi-dir() {
right: 0;
left: auto;
/* stylelint-enable property-blacklist */
/* stylelint-enable property-disallowed-list */
}
}

View File

@@ -24,11 +24,11 @@ export const createSwipeToCloseGesture = (
return true;
}
const content = target.closest('ion-content');
if (content === null) {
const contentOrFooter = target.closest('ion-content, ion-footer');
if (contentOrFooter === null) {
return true;
}
// Target is in the content so we don't start the gesture.
// Target is in the content or the footer so do not start the gesture.
// We could be more nuanced here and allow it for content that
// does not need to scroll.
return false;

View File

@@ -1,3 +1,5 @@
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode } from '../../interface';
export interface ModalOptions<T extends ComponentRef = ComponentRef> {
@@ -14,7 +16,10 @@ export interface ModalOptions<T extends ComponentRef = ComponentRef> {
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: ModalAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface ModalAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}

View File

@@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Meth
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Gesture, OverlayEventDetail, OverlayInterface } from '../../interface';
import { Animation, AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Gesture, ModalAttributes, OverlayEventDetail, OverlayInterface } from '../../interface';
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
import { BACKDROP, activeAnimations, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -102,6 +102,11 @@ export class Modal implements ComponentInterface, OverlayInterface {
*/
@Prop() presentingElement?: HTMLElement;
/**
* Additional attributes to pass to the modal.
*/
@Prop() htmlAttributes?: ModalAttributes;
/**
* Emitted after the modal has presented.
*/
@@ -265,6 +270,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
}
render() {
const { htmlAttributes } = this;
const mode = getIonMode(this);
return (
@@ -272,14 +278,15 @@ export class Modal implements ComponentInterface, OverlayInterface {
no-router
aria-modal="true"
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${20000 + this.overlayIndex}`,
}}
class={{
[mode]: true,
[`modal-card`]: this.presentingElement !== undefined && mode === 'ios',
...getClassMap(this.cssClass)
}}
style={{
zIndex: `${20000 + this.overlayIndex}`,
}}
onIonBackdropTap={this.onBackdropTap}
onIonDismiss={this.onDismiss}
onIonModalDidPresent={this.onLifecycle}

View File

@@ -42,6 +42,37 @@ ion-modal.stack-modal {
}
```
## Interfaces
### ModalOptions
```typescript
interface ModalOptions<T extends ComponentRef = ComponentRef> {
component: T;
componentProps?: ComponentProps<T>;
presentingElement?: HTMLElement;
showBackdrop?: boolean;
backdropDismiss?: boolean;
cssClass?: string | string[];
animated?: boolean;
swipeToClose?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: ModalAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### ModalAttributes
```typescript
interface ModalAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
<!-- Auto Generated Below -->
@@ -489,6 +520,7 @@ In most scenarios, setting a ref on `IonRouterOutlet` and passing that ref's `cu
isOpen={show2ndModal}
cssClass='my-custom-class'
presentingElement={firstModalRef.current}
swipeToClose={true}
onDidDismiss={() => setShow2ndModal(false)}>
<p>This is more modal content</p>
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
@@ -751,6 +783,47 @@ export default defineComponent({
> If you need a wrapper element inside of your modal component, we recommend using an `<ion-page>` so that the component dimensions are still computed properly.
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
> Card style modals when running on iPhone-sized devices do not have backdrops. As a result, the `--backdrop-opacity` variable will not have any effect.
```html
<template>
<ion-page>
<ion-content>
<ion-button @click="setOpen(true)">Show Modal</ion-button>
<ion-modal
:is-open="isOpenRef"
css-class="my-custom-class"
:swipe-to-close="true"
:presenting-element="$parent.$refs.ionRouterOutlet"
@didDismiss="setOpen(false)"
>
<Modal :data="data"></Modal>
</ion-modal>
</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonModal, IonButton, IonContent, IonPage } from '@ionic/vue';
import { defineComponent, ref } from 'vue';
import Modal from './modal.vue'
export default defineComponent({
components: { IonModal, IonButton, Modal, IonContent, IonPage },
setup() {
const isOpenRef = ref(false);
const setOpen = (state: boolean) => isOpenRef.value = state;
const data = { content: 'New Content' };
return { isOpenRef, setOpen, data }
}
});
</script>
```
## Properties
@@ -763,6 +836,7 @@ export default defineComponent({
| `componentProps` | -- | The data to pass to the modal component. | `undefined \| { [key: string]: any; }` | `undefined` |
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the modal is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the modal. | `ModalAttributes \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the modal is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |

View File

@@ -71,3 +71,19 @@ test('modal: basic', async () => {
test('modal:rtl: basic', async () => {
await testModal(DIRECTORY, '#basic-modal', true);
});
test('modal: htmlAttributes', async () => {
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
await page.click('#basic-modal');
await page.waitForSelector('#basic-modal');
let alert = await page.find('ion-modal');
expect(alert).not.toBe(null);
await alert.waitForVisible();
const attribute = await page.evaluate((el) => document.querySelector('ion-modal').getAttribute('data-testid'));
expect(attribute).toEqual('basic-modal');
});

View File

@@ -67,7 +67,10 @@
// present the modal
const modalElement = Object.assign(document.createElement('ion-modal'), {
component: element
component: element,
htmlAttributes: {
'data-testid': 'basic-modal'
}
});
// listen for close event
const button = element.querySelector('ion-button');

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Modal - Basic</title>
<title>Modal - Custom</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
@@ -11,22 +11,27 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.custom-modal {
--height: 70%;
--border-style: solid;
--border-width: 7px 0 0 0;
--border-color: #0d51aa;
--border-radius: 20px 20px 0 0;
align-items: flex-end;
}
@media (max-width: 400px) {
.custom-modal {
--max-width: 98%;
--height: 98%;
--height: 70%;
--border-style: solid;
--border-width: 7px 0 0 0;
--border-color: #0d51aa;
--border-radius: 20px 20px 0 0;
align-items: flex-end;
}
.custom-modal ion-toolbar {
--padding-top: 46px;
--padding-bottom: 10px;
}
@media (max-width: 400px) {
.custom-modal {
--max-width: 98%;
--height: 98%;
}
}
}
</style>
</head>
@@ -35,7 +40,7 @@
<ion-header>
<ion-toolbar>
<ion-title>Modal - Basic</ion-title>
<ion-title>Modal - Custom</ion-title>
</ion-toolbar>
</ion-header>
@@ -55,13 +60,23 @@
element.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button>
<ion-icon slot="icon-only" name="add-circle-outline"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Super Modal</ion-title>
<ion-buttons slot="end">
<ion-button class="dismiss">
Close
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<h1>Content of doom</h1>
<div>Here's some more content</div>
<ion-button class="dismiss">Dismiss Modal</ion-button>
<ion-button class="dismiss" class="dismiss">Dismiss Modal</ion-button>
</ion-content>
`;
@@ -72,10 +87,12 @@
});
// listen for close event
const button = element.querySelector('ion-button');
button.addEventListener('click', () => {
modalElement.dismiss();
});
const buttons = element.querySelectorAll('.dismiss');
for (var button of buttons) {
button.addEventListener('click', () => {
modalElement.dismiss();
});
}
document.body.appendChild(modalElement);
return modalElement;
}

View File

@@ -147,6 +147,7 @@ In most scenarios, setting a ref on `IonRouterOutlet` and passing that ref's `cu
isOpen={show2ndModal}
cssClass='my-custom-class'
presentingElement={firstModalRef.current}
swipeToClose={true}
onDidDismiss={() => setShow2ndModal(false)}>
<p>This is more modal content</p>
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>

View File

@@ -93,3 +93,44 @@ export default defineComponent({
```
> If you need a wrapper element inside of your modal component, we recommend using an `<ion-page>` so that the component dimensions are still computed properly.
### Swipeable Modals
Modals in iOS mode have the ability to be presented in a card-style and swiped to close. The card-style presentation and swipe to close gesture are not mutually exclusive, meaning you can pick and choose which features you want to use. For example, you can have a card-style modal that cannot be swiped or a full sized modal that can be swiped.
> Card style modals when running on iPhone-sized devices do not have backdrops. As a result, the `--backdrop-opacity` variable will not have any effect.
```html
<template>
<ion-page>
<ion-content>
<ion-button @click="setOpen(true)">Show Modal</ion-button>
<ion-modal
:is-open="isOpenRef"
css-class="my-custom-class"
:swipe-to-close="true"
:presenting-element="$parent.$refs.ionRouterOutlet"
@didDismiss="setOpen(false)"
>
<Modal :data="data"></Modal>
</ion-modal>
</ion-content>
</ion-page>
</template>
<script lang="ts">
import { IonModal, IonButton, IonContent, IonPage } from '@ionic/vue';
import { defineComponent, ref } from 'vue';
import Modal from './modal.vue'
export default defineComponent({
components: { IonModal, IonButton, Modal, IonContent, IonPage },
setup() {
const isOpenRef = ref(false);
const setOpen = (state: boolean) => isOpenRef.value = state;
const data = { content: 'New Content' };
return { isOpenRef, setOpen, data }
}
});
</script>
```

View File

@@ -872,14 +872,15 @@ export class Nav implements NavOutlet {
mode,
showGoBack: this.canGoBackSync(enteringView),
baseEl: this.el,
animationBuilder: this.animation || opts.animationBuilder || config.get('navAnimation'),
progressCallback,
animated: this.animated && config.getBoolean('animated', true),
enteringEl,
leavingEl,
...opts
...opts,
animationBuilder: opts.animationBuilder || this.animation || config.get('navAnimation')
};
const { hasCompleted } = await transition(animationOpts);
return this.transitionFinish(hasCompleted, enteringView, leavingView, opts);

View File

@@ -169,7 +169,7 @@ describe('NavController', () => {
describe('insert', () => {
it('should insert at the begining with no async transition', async () => {
it('should insert at the beginning with no async transition', async () => {
const view4 = mockView(MockView4);
const instance4 = spyOnLifecycles(view4);
const opts: NavOptions = {};

View File

@@ -1,3 +1,5 @@
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, Mode } from '../../interface';
export interface PickerOptions {
@@ -11,11 +13,14 @@ export interface PickerOptions {
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: PickerAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface PickerAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
export interface PickerButton {
text?: string;
role?: string;

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, State, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface, PickerButton, PickerColumn } from '../../interface';
import { AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface, PickerAttributes, PickerButton, PickerColumn } from '../../interface';
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -81,6 +81,11 @@ export class Picker implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* Additional attributes to pass to the picker.
*/
@Prop() htmlAttributes?: PickerAttributes;
/**
* Emitted after the picker has presented.
*/
@@ -213,11 +218,16 @@ export class Picker implements ComponentInterface, OverlayInterface {
}
render() {
const { htmlAttributes } = this;
const mode = getIonMode(this);
return (
<Host
aria-modal="true"
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${20000 + this.overlayIndex}`
}}
class={{
[mode]: true,
@@ -226,9 +236,6 @@ export class Picker implements ComponentInterface, OverlayInterface {
...getClassMap(this.cssClass)
}}
style={{
zIndex: `${20000 + this.overlayIndex}`
}}
onIonBackdropTap={this.onBackdropTap}
onIonPickerWillDismiss={this.dispatchCancelHandler}
>

View File

@@ -2,7 +2,78 @@
A Picker is a dialog that displays a row of buttons and columns underneath. It appears on top of the app's content, and at the bottom of the viewport.
## Interfaces
### PickerButton
```typescript
interface PickerButton {
text?: string;
role?: string;
cssClass?: string | string[];
handler?: (value: any) => boolean | void;
}
```
### PickerColumn
```typescript
interface PickerColumn {
name: string;
align?: string;
selectedIndex?: number;
prevSelected?: number;
prefix?: string;
suffix?: string;
options: PickerColumnOption[];
cssClass?: string | string[];
columnWidth?: string;
prefixWidth?: string;
suffixWidth?: string;
optionsWidth?: string;
refresh?: () => void;
}
```
### PickerColumnOption
```typescript
interface PickerColumnOption {
text?: string;
value?: any;
disabled?: boolean;
duration?: number;
transform?: string;
selected?: boolean;
}
```
### PickerOptions
```typescript
interface PickerOptions {
columns: PickerColumn[];
buttons?: PickerButton[];
cssClass?: string | string[];
showBackdrop?: boolean;
backdropDismiss?: boolean;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: PickerAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### PickerAttributes
```typescript
interface PickerAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
<!-- Auto Generated Below -->
@@ -95,6 +166,63 @@ const PickerExample: React.FC = () => {
```
### Vue
```vue
<template>
<div>
<ion-button @click="openPicker">SHOW PICKER</ion-button>
<p v-if="picked.animal">picked: {{ picked.animal.text }}</p>
</div>
</template>
<script>
import { IonButton, pickerController } from "@ionic/vue";
export default {
components: {
IonButton,
},
data() {
return {
pickingOptions: {
name: "animal",
options: [
{ text: "Dog", value: "dog" },
{ text: "Cat", value: "cat" },
{ text: "Bird", value: "bird" },
],
},
picked: {
animal: "",
},
};
},
methods: {
async openPicker() {
const picker = await pickerController.create({
columns: [this.pickingOptions],
buttons: [
{
text: "Cancel",
role: "cancel",
},
{
text: "Confirm",
handler: (value) => {
this.picked = value;
console.log(`Got Value ${value}`);
},
},
],
});
await picker.present();
},
},
};
</script>
```
## Properties
@@ -107,6 +235,7 @@ const PickerExample: React.FC = () => {
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `duration` | `duration` | Number of milliseconds to wait before dismissing the picker. | `number` | `0` |
| `enterAnimation` | -- | Animation to use when the picker is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the picker. | `PickerAttributes \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the picker is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |

View File

@@ -115,6 +115,9 @@
value: '12'
}]
}],
htmlAttributes: {
'data-testid': 'basic-picker'
}
cssClass: customClass
});

View File

@@ -0,0 +1,53 @@
```vue
<template>
<div>
<ion-button @click="openPicker">SHOW PICKER</ion-button>
<p v-if="picked.animal">picked: {{ picked.animal.text }}</p>
</div>
</template>
<script>
import { IonButton, pickerController } from "@ionic/vue";
export default {
components: {
IonButton,
},
data() {
return {
pickingOptions: {
name: "animal",
options: [
{ text: "Dog", value: "dog" },
{ text: "Cat", value: "cat" },
{ text: "Bird", value: "bird" },
],
},
picked: {
animal: "",
},
};
},
methods: {
async openPicker() {
const picker = await pickerController.create({
columns: [this.pickingOptions],
buttons: [
{
text: "Cancel",
role: "cancel",
},
{
text: "Confirm",
handler: (value) => {
this.picked = value;
console.log(`Got Value ${value}`);
},
},
],
});
await picker.present();
},
},
};
</script>
```

View File

@@ -1,3 +1,5 @@
import { JSXBase } from '@stencil/core/internal';
import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode } from '../../interface';
export interface PopoverOptions<T extends ComponentRef = ComponentRef> {
@@ -14,7 +16,10 @@ export interface PopoverOptions<T extends ComponentRef = ComponentRef> {
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: PopoverAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface PopoverAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}

View File

@@ -1,7 +1,7 @@
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface } from '../../interface';
import { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, OverlayEventDetail, OverlayInterface, PopoverAttributes } from '../../interface';
import { attachComponent, detachComponent } from '../../utils/framework-delegate';
import { BACKDROP, dismiss, eventMethod, prepareOverlay, present } from '../../utils/overlays';
import { getClassMap } from '../../utils/theme';
@@ -96,6 +96,11 @@ export class Popover implements ComponentInterface, OverlayInterface {
*/
@Prop() animated = true;
/**
* Additional attributes to pass to the popover.
*/
@Prop() htmlAttributes?: PopoverAttributes;
/**
* Emitted after the popover has presented.
*/
@@ -198,12 +203,13 @@ export class Popover implements ComponentInterface, OverlayInterface {
render() {
const mode = getIonMode(this);
const { onLifecycle } = this;
const { onLifecycle, htmlAttributes } = this;
return (
<Host
aria-modal="true"
no-router
tabindex="-1"
{...htmlAttributes as any}
style={{
zIndex: `${20000 + this.overlayIndex}`,
}}

View File

@@ -34,6 +34,36 @@ Any of the defined [CSS Custom Properties](#css-custom-properties) can be used t
> If you are building an Ionic Angular app, the styles need to be added to a global stylesheet file. Read [Style Placement](#style-placement) in the Angular section below for more information.
## Interfaces
### PopoverOptions
```typescript
interface PopoverOptions {
component: any;
componentProps?: { [key: string]: any };
showBackdrop?: boolean;
backdropDismiss?: boolean;
translucent?: boolean;
cssClass?: string | string[];
event?: Event;
animated?: boolean;
mode?: 'ios' | 'md';
keyboardClose?: boolean;
id?: string;
htmlAttributes?: PopoverAttributes;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
```
### PopoverAttributes
```typescript
interface PopoverAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
```
<!-- Auto Generated Below -->
@@ -346,8 +376,8 @@ export default defineComponent({
setup() {
const isOpenRef = ref(false);
const event = ref();
const setOpen = (state: boolean, event?: Event) => {
event.value = event;
const setOpen = (state: boolean, ev?: Event) => {
event.value = ev;
isOpenRef.value = state;
}
return { isOpenRef, setOpen, event }
@@ -369,6 +399,7 @@ export default defineComponent({
| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
| `enterAnimation` | -- | Animation to use when the popover is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `event` | `event` | The event to pass to the popover animation. | `any` | `undefined` |
| `htmlAttributes` | -- | Additional attributes to pass to the popover. | `PopoverAttributes \| undefined` | `undefined` |
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
| `leaveAnimation` | -- | Animation to use when the popover is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |

View File

@@ -80,3 +80,19 @@ test('popover:rtl: no event', async () => {
test('popover:rtl: custom class', async () => {
await testPopover(DIRECTORY, '#custom-class-popover', true);
});
test('popover: htmlAttributes', async () => {
const page = await newE2EPage({ url: '/src/components/popover/test/basic?ionic:_testing=true' });
await page.click('#basic-popover');
await page.waitForSelector('#basic-popover');
let alert = await page.find('ion-popover');
expect(alert).not.toBe(null);
await alert.waitForVisible();
const attribute = await page.evaluate((el) => document.querySelector('ion-popover').getAttribute('data-testid'));
expect(attribute).toEqual('basic-popover');
});

View File

@@ -29,7 +29,7 @@
</ion-header>
<ion-content class="ion-padding" id="content">
<ion-button id="basic-popover" expand="block" onclick="presentPopover({ component: 'profile-page', event: event })">Show Popover</ion-button>
<ion-button id="basic-popover" expand="block" onclick="presentPopover({ component: 'profile-page', event: event, htmlAttributes: { 'data-testid': 'basic-popover' } })">Show Popover</ion-button>
<ion-button id="translucent-popover" expand="block" onclick="presentPopover({ component: 'translucent-page', event: event, translucent: true })">Show Translucent Popover</ion-button>
<ion-button id="long-list-popover" expand="block" color="secondary" onclick="presentPopover({ component: 'list-page', event: event })">Show Long List Popover</ion-button>
<ion-button id="no-event-popover" expand="block" color="danger" onclick="presentPopover({ component: 'profile-page' })">No Event Popover</ion-button>

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