diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index b1c6055fea..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-name: Bug Report
-about: Create a report to help us improve
-title: 'bug: '
-labels: ''
-assignees: ''
----
-
-
-
-
-
-
-
-
-
-# Bug Report
-
-**Ionic version:**
-
-
-[ ] **4.x**
-[ ] **5.x**
-[ ] **6.x**
-
-**Current behavior:**
-
-
-**Expected behavior:**
-
-
-**Steps to reproduce:**
-
-
-**Related code:**
-
-
-
-```
-insert short code snippets here
-```
-
-**Other information:**
-
-
-**Ionic info:**
-
-
-```
-insert the output from ionic info here
-```
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..d7e064089f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,56 @@
+name: 🐛 Bug Report
+description: Create a report to help us improve Ionic Framework
+title: 'bug: '
+body:
+ - type: checkboxes
+ attributes:
+ label: Prequisites
+ 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.
diff --git a/.github/ISSUE_TEMPLATE/cli.md b/.github/ISSUE_TEMPLATE/cli.md
deleted file mode 100644
index 213bc40092..0000000000
--- a/.github/ISSUE_TEMPLATE/cli.md
+++ /dev/null
@@ -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).
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..25a8dbb606
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -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.
diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md
deleted file mode 100644
index 255df15c4c..0000000000
--- a/.github/ISSUE_TEMPLATE/documentation.md
+++ /dev/null
@@ -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).
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index b798af2804..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-name: Feature Request
-about: Suggest an idea for this project
-title: 'feat: '
-labels: ''
-assignees: ''
----
-
-
-
-
-
-
-
-
-
-# Feature Request
-
-**Ionic version:**
-
-
-[ ] **4.x**
-[ ] **5.x**
-[ ] **6.x**
-
-**Describe the Feature Request**
-
-
-**Describe Preferred Solution**
-
-
-**Describe Alternatives**
-
-
-**Related Code**
-
-
-**Additional Context**
-
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000000..2a955b4446
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,43 @@
+name: 💡 Feature Request
+description: Suggest an idea for Ionic Framework
+title: 'feat: '
+body:
+ - type: checkboxes
+ attributes:
+ label: Prequisites
+ 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.
diff --git a/.github/ISSUE_TEMPLATE/support_question.md b/.github/ISSUE_TEMPLATE/support_question.md
deleted file mode 100644
index c72195f886..0000000000
--- a/.github/ISSUE_TEMPLATE/support_question.md
+++ /dev/null
@@ -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/
diff --git a/angular/src/index.ts b/angular/src/index.ts
index ba5be94e54..c116ef2076 100644
--- a/angular/src/index.ts
+++ b/angular/src/index.ts
@@ -46,4 +46,44 @@ export { IonicModule } from './ionic-module';
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';
diff --git a/core/.stylelintrc.yml b/core/.stylelintrc.yml
index 6cd3fda7b9..70a8b0c17b 100644
--- a/core/.stylelintrc.yml
+++ b/core/.stylelintrc.yml
@@ -254,7 +254,7 @@ rules:
- visibility
- z-index
- property-blacklist:
+ property-disallowed-list:
- background-position
- right
- left
diff --git a/core/src/components/action-sheet/action-sheet.ios.scss b/core/src/components/action-sheet/action-sheet.ios.scss
index 126e346f8e..4bd0540db8 100644
--- a/core/src/components/action-sheet/action-sheet.ios.scss
+++ b/core/src/components/action-sheet/action-sheet.ios.scss
@@ -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;
}
diff --git a/core/src/components/action-sheet/action-sheet.ios.vars.scss b/core/src/components/action-sheet/action-sheet.ios.vars.scss
index 137d19a260..f984d4902e 100644
--- a/core/src/components/action-sheet/action-sheet.ios.vars.scss
+++ b/core/src/components/action-sheet/action-sheet.ios.vars.scss
@@ -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;
diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx
index 130dd09c92..13879dc310 100644
--- a/core/src/components/action-sheet/action-sheet.tsx
+++ b/core/src/components/action-sheet/action-sheet.tsx
@@ -258,7 +258,10 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
setShow2ndModal(false)}>Close Modal
@@ -811,6 +836,47 @@ export default defineComponent({
> If you need a wrapper element inside of your modal component, we recommend using an `` 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
+
+
+
+ Show Modal
+
+
+
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/modal/usage/react.md b/core/src/components/modal/usage/react.md
index 1aecc080c8..702e17f681 100644
--- a/core/src/components/modal/usage/react.md
+++ b/core/src/components/modal/usage/react.md
@@ -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)}>
This is more modal content
setShow2ndModal(false)}>Close Modal
diff --git a/core/src/components/modal/usage/vue.md b/core/src/components/modal/usage/vue.md
index 47afb4083d..86d06cc394 100644
--- a/core/src/components/modal/usage/vue.md
+++ b/core/src/components/modal/usage/vue.md
@@ -93,3 +93,44 @@ export default defineComponent({
```
> If you need a wrapper element inside of your modal component, we recommend using an `` 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
+
+
+
+ Show Modal
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/core/src/components/nav/test/nav-controller.spec.ts b/core/src/components/nav/test/nav-controller.spec.ts
index e6a6eab9ce..cca03cc5ed 100644
--- a/core/src/components/nav/test/nav-controller.spec.ts
+++ b/core/src/components/nav/test/nav-controller.spec.ts
@@ -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 = {};
diff --git a/core/src/components/picker/readme.md b/core/src/components/picker/readme.md
index bcae3a1a86..e1f001b448 100644
--- a/core/src/components/picker/readme.md
+++ b/core/src/components/picker/readme.md
@@ -2,7 +2,71 @@
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;
+
+ enterAnimation?: AnimationBuilder;
+ leaveAnimation?: AnimationBuilder;
+}
+```
diff --git a/core/src/components/popover/readme.md b/core/src/components/popover/readme.md
index af22da4d6c..1dc57ea4a6 100644
--- a/core/src/components/popover/readme.md
+++ b/core/src/components/popover/readme.md
@@ -36,47 +36,6 @@ If you need fine grained control over when the popover is presented and dismisse
We typically recommend that you write your popovers inline as it streamlines the amount of code in your application. You should only use the `popoverController` for complex use cases where writing a popover inline is impractical. When using a controller, your popover is not created ahead of time, so properties such as `trigger` and `trigger-action` are not applicable here. In addition, nested popovers are not compatible with the controller approach because the popover is automatically added to the root of your application when the `create` method is called.
-## Interfaces
-
-Below you will find all of the options available to you when using the `popoverController`. These options should be supplied when calling `popoverController.create()`.
-
-```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;
-
- enterAnimation?: AnimationBuilder;
- leaveAnimation?: AnimationBuilder;
-
- size?: PopoverSize;
- dismissOnSelect?: boolean;
- reference?: PositionReference;
- side?: PositionSide;
- align?: PositionAlign;
-}
-```
-
-## Types
-
-Below you will find all of the custom types for `ion-popover`:
-
-```typescript
-type PopoverSize = 'cover' | 'auto';
-type TriggerAction = 'click' | 'hover' | 'context-menu';
-type PositionReference = 'trigger' | 'event';
-type PositionSide = 'top' | 'right' | 'bottom' | 'left' | 'start' | 'end';
-type PositionAlign = 'start' | 'center' | 'end';
-```
## Customization
@@ -155,6 +114,48 @@ You can use the `dismissOnSelect` property to automatically close the popover wh
> Nested popovers cannot be created when using the `popoverController` because the popover is automatically added to the root of your application when the `create` method is called.
+## Interfaces
+
+Below you will find all of the options available to you when using the `popoverController`. These options should be supplied when calling `popoverController.create()`.
+
+```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;
+
+ enterAnimation?: AnimationBuilder;
+ leaveAnimation?: AnimationBuilder;
+
+ size?: PopoverSize;
+ dismissOnSelect?: boolean;
+ reference?: PositionReference;
+ side?: PositionSide;
+ align?: PositionAlign;
+}
+```
+
+## Types
+
+Below you will find all of the custom types for `ion-popover`:
+
+```typescript
+type PopoverSize = 'cover' | 'auto';
+type TriggerAction = 'click' | 'hover' | 'context-menu';
+type PositionReference = 'trigger' | 'event';
+type PositionSide = 'top' | 'right' | 'bottom' | 'left' | 'start' | 'end';
+type PositionAlign = 'start' | 'center' | 'end';
+```
+
## Accessibility
### Keyboard Navigation
diff --git a/core/src/components/progress-bar/progress-bar.scss b/core/src/components/progress-bar/progress-bar.scss
index d9bc8dfe0c..0752c79d17 100644
--- a/core/src/components/progress-bar/progress-bar.scss
+++ b/core/src/components/progress-bar/progress-bar.scss
@@ -46,10 +46,10 @@
// Extend a bit to overflow. The size of animated distance.
.buffer-circles {
- /* stylelint-disable property-blacklist */
+ /* stylelint-disable property-disallowed-list */
right: -10px;
left: -10px;
- /* stylelint-enable property-blacklist */
+ /* stylelint-enable property-disallowed-list */
}
// Determinate progress bar
@@ -58,7 +58,7 @@
.progress,
.progress-buffer-bar,
.buffer-circles-container {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
transform-origin: left top;
transition: transform 150ms linear;
@@ -88,12 +88,12 @@
// --------------------------------------------------
.indeterminate-bar-primary {
- /* stylelint-disable property-blacklist */
+ /* stylelint-disable property-disallowed-list */
top: 0;
right: 0;
bottom: 0;
left: -145.166611%;
- /* stylelint-enable property-blacklist */
+ /* stylelint-enable property-disallowed-list */
animation: primary-indeterminate-translate 2s infinite linear;
@@ -104,12 +104,12 @@
}
.indeterminate-bar-secondary {
- /* stylelint-disable property-blacklist */
+ /* stylelint-disable property-disallowed-list */
top: 0;
right: 0;
bottom: 0;
left: -54.888891%;
- /* stylelint-enable property-blacklist */
+ /* stylelint-enable property-disallowed-list */
animation: secondary-indeterminate-translate 2s infinite linear;
@@ -125,11 +125,11 @@
.buffer-circles {
background-image: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%);
- /* stylelint-disable property-blacklist */
+ /* stylelint-disable property-disallowed-list */
background-repeat: repeat-x;
background-position: 5px center;
background-size: 10px 10px;
- /* stylelint-enable property-blacklist */
+ /* stylelint-enable property-disallowed-list */
z-index: 0;
animation: buffering 450ms infinite linear;
diff --git a/core/src/components/range/range.md.scss b/core/src/components/range/range.md.scss
index 52aa9b23aa..987f286e90 100644
--- a/core/src/components/range/range.md.scss
+++ b/core/src/components/range/range.md.scss
@@ -105,12 +105,12 @@
@include margin-horizontal(-13px, null);
@include multi-dir() {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
border-radius: 50% 50% 50% 0;
}
@include rtl() {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
left: unset;
}
diff --git a/core/src/components/range/range.scss b/core/src/components/range/range.scss
index 89e6ab6cbb..10c92149b1 100644
--- a/core/src/components/range/range.scss
+++ b/core/src/components/range/range.scss
@@ -82,7 +82,7 @@
);
@include rtl() {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
left: unset;
}
@@ -104,7 +104,7 @@
@include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0);
@include rtl() {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
left: unset;
}
@@ -127,7 +127,7 @@
);
@include rtl() {
- /* stylelint-disable-next-line property-blacklist */
+ /* stylelint-disable-next-line property-disallowed-list */
left: unset;
}
diff --git a/core/src/components/router-outlet/readme.md b/core/src/components/router-outlet/readme.md
index 9e7883c0b3..2c6d5917e3 100644
--- a/core/src/components/router-outlet/readme.md
+++ b/core/src/components/router-outlet/readme.md
@@ -1,8 +1,8 @@
# ion-router-outlet
-Router outlet is a component used in routing within an Angular or Vue app. It behaves in a similar way to Angular's built-in router outlet component and Vue's router view component, but contains the logic for providing a stacked navigation, and animating views in and out.
+Router outlet is a component used in routing within an Angular, React, or Vue app. It behaves in a similar way to Angular's built-in router outlet component and Vue's router view component, but contains the logic for providing a stacked navigation, and animating views in and out.
-> Note: this component should only be used with Angular and Vue projects. For vanilla or Stencil JavaScript projects, use [`ion-router`](../router) and [`ion-route`](../route).
+> Note: this component should only be used with Angular, React, and Vue projects. For vanilla or Stencil JavaScript projects, use [`ion-router`](../router) and [`ion-route`](../route).
Although router outlet has methods for navigating around, it's recommended to use the navigation methods in your framework's router.
diff --git a/core/src/components/router-outlet/route-outlet.tsx b/core/src/components/router-outlet/route-outlet.tsx
index bba06a8c63..fe81399802 100644
--- a/core/src/components/router-outlet/route-outlet.tsx
+++ b/core/src/components/router-outlet/route-outlet.tsx
@@ -19,7 +19,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
private waitPromise?: Promise;
private gesture?: Gesture;
private ani?: Animation;
- private animationEnabled = true;
+ private gestureOrAnimationInProgress = false;
@Element() el!: HTMLElement;
@@ -61,17 +61,22 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
@Event({ bubbles: false }) ionNavDidChange!: EventEmitter;
async connectedCallback() {
+ const onStart = () => {
+ this.gestureOrAnimationInProgress = true;
+ if (this.swipeHandler) {
+ this.swipeHandler.onStart();
+ }
+ }
+
this.gesture = (await import('../../utils/gesture/swipe-back')).createSwipeBackGesture(
this.el,
- () => !!this.swipeHandler && this.swipeHandler.canStart() && this.animationEnabled,
- () => this.swipeHandler && this.swipeHandler.onStart(),
+ () => !this.gestureOrAnimationInProgress && !!this.swipeHandler && this.swipeHandler.canStart(),
+ () => onStart(),
step => this.ani && this.ani.progressStep(step),
(shouldComplete, step, dur) => {
if (this.ani) {
- this.animationEnabled = false;
-
this.ani.onFinish(() => {
- this.animationEnabled = true;
+ this.gestureOrAnimationInProgress = false;
if (this.swipeHandler) {
this.swipeHandler.onEnd(shouldComplete);
@@ -97,7 +102,8 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
}
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
-
+ } else {
+ this.gestureOrAnimationInProgress = false;
}
}
);
@@ -191,7 +197,34 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
leavingEl,
baseEl: el,
progressCallback: (opts.progressAnimation
- ? ani => this.ani = ani
+ ? ani => {
+ /**
+ * Because this progress callback is called asynchronously
+ * it is possible for the gesture to start and end before
+ * the animation is ever set. In that scenario, we should
+ * immediately call progressEnd so that the transition promise
+ * resolves and the gesture does not get locked up.
+ */
+ if (ani !== undefined && !this.gestureOrAnimationInProgress) {
+ this.gestureOrAnimationInProgress = true;
+ ani.onFinish(() => {
+ this.gestureOrAnimationInProgress = false;
+ if (this.swipeHandler) {
+ this.swipeHandler.onEnd(false);
+ }
+ }, { oneTimeCallback: true });
+
+ /**
+ * Playing animation to beginning
+ * with a duration of 0 prevents
+ * any flickering when the animation
+ * is later cleaned up.
+ */
+ ani.progressEnd(0, 0, 0);
+ } else {
+ this.ani = ani;
+ }
+ }
: undefined
),
...opts,
diff --git a/core/src/components/skeleton-text/skeleton-text.scss b/core/src/components/skeleton-text/skeleton-text.scss
index 0f7a69c0f1..455fe41ade 100644
--- a/core/src/components/skeleton-text/skeleton-text.scss
+++ b/core/src/components/skeleton-text/skeleton-text.scss
@@ -61,7 +61,7 @@ span {
animation-timing-function: linear;
}
-/* stylelint-disable property-blacklist */
+/* stylelint-disable property-disallowed-list */
@keyframes shimmer {
0% {
background-position: -400px 0;
@@ -71,4 +71,4 @@ span {
background-position: 400px 0;
}
}
-/* stylelint-enable property-blacklist */
+/* stylelint-enable property-disallowed-list */
diff --git a/core/src/components/toast/readme.md b/core/src/components/toast/readme.md
index a345835716..ea6324d5b5 100644
--- a/core/src/components/toast/readme.md
+++ b/core/src/components/toast/readme.md
@@ -10,6 +10,43 @@ Toasts can be positioned at the top, bottom or middle of the viewport. The posit
The toast can be dismissed automatically after a specific amount of time by passing the number of milliseconds to display it in the `duration` of the toast options. If a button with a role of `"cancel"` is added, then that button will dismiss the toast. To dismiss the toast after creation, call the `dismiss()` method on the instance.
+## Interfaces
+
+### ToastButton
+
+```typescript
+interface ToastButton {
+ text?: string;
+ icon?: string;
+ side?: 'start' | 'end';
+ role?: 'cancel' | string;
+ cssClass?: string | string[];
+ handler?: () => boolean | void | Promise;
+}
+```
+
+### ToastOptions
+
+```typescript
+interface ToastOptions {
+ header?: string;
+ message?: string | IonicSafeString;
+ cssClass?: string | string[];
+ duration?: number;
+ buttons?: (ToastButton | string)[];
+ position?: 'top' | 'bottom' | 'middle';
+ translucent?: boolean;
+ animated?: boolean;
+
+ color?: Color;
+ mode?: Mode;
+ keyboardClose?: boolean;
+ id?: string;
+
+ enterAnimation?: AnimationBuilder;
+ leaveAnimation?: AnimationBuilder;
+}
+```
diff --git a/core/src/components/virtual-scroll/virtual-scroll.scss b/core/src/components/virtual-scroll/virtual-scroll.scss
index df56ac21e3..00ff1c872c 100644
--- a/core/src/components/virtual-scroll/virtual-scroll.scss
+++ b/core/src/components/virtual-scroll/virtual-scroll.scss
@@ -16,7 +16,7 @@ ion-virtual-scroll > .virtual-loading {
}
ion-virtual-scroll > .virtual-item {
- /* stylelint-disable declaration-no-important, property-blacklist */
+ /* stylelint-disable declaration-no-important, property-disallowed-list */
position: absolute !important;
top: 0 !important;
diff --git a/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js b/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js
index a7e721ccd2..973ec70da4 100644
--- a/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js
+++ b/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js
@@ -10,6 +10,7 @@ describe('Swipe To Go Back', () => {
cy.ionPageVisible('main');
cy.ionNav('ion-item', 'Details');
cy.ionPageVisible('details');
+ cy.ionPageHidden('main');
cy.ionSwipeToGoBack(true);
cy.ionPageVisible('main');
});
diff --git a/packages/react/README.md b/packages/react/README.md
index fec4540857..9ec88af101 100644
--- a/packages/react/README.md
+++ b/packages/react/README.md
@@ -2,7 +2,7 @@
These are React specific building blocks on top of [@ionic/core](https://www.npmjs.com/package/@ionic/core) components/services.
-To get started, install the Ionic CLI by running `npm i -g ionic`. Then, start a new Ionic React Project by running `ionic start myapp --type=react`.
+To get started, install the Ionic CLI by running `npm i -g @ionic/cli`. Then, start a new Ionic React Project by running `ionic start myapp --type=react`.
# Current Status of Components
diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts
index 5beed3e662..103889dd27 100644
--- a/packages/react/src/components/index.ts
+++ b/packages/react/src/components/index.ts
@@ -26,8 +26,6 @@ export {
AnimationLifecycle,
createAnimation,
createGesture,
- AlertButton,
- AlertInput,
Gesture,
GestureConfig,
GestureDetail,
@@ -36,7 +34,33 @@ export {
mdTransitionAnimation,
NavComponentWithProps,
setupConfig,
+
IonicSwiper,
+
+ SpinnerTypes,
+
+ ActionSheetOptions,
+ ActionSheetButton,
+
+ AlertOptions,
+ AlertInput,
+ AlertTextareaAttributes,
+ AlertInputAttributes,
+ AlertButton,
+
+ LoadingOptions,
+
+ ModalOptions,
+
+ PickerOptions,
+ PickerButton,
+ PickerColumn,
+ PickerColumnOption,
+
+ PopoverOptions,
+
+ ToastOptions,
+ ToastButton
} from '@ionic/core';
export * from './proxies';
diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts
index 958f252891..14a2ea808f 100644
--- a/packages/vue/src/components/IonRouterOutlet.ts
+++ b/packages/vue/src/components/IonRouterOutlet.ts
@@ -311,6 +311,17 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
if (!enteringViewItem) {
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
viewStacks.add(enteringViewItem);
+
+ /**
+ * All views that can be transitioned to must have
+ * an `` element for transitions and lifecycle
+ * methods to work properly.
+ */
+ if (enteringViewItem.vueComponent?.components?.IonPage === undefined) {
+ console.warn(`[@ionic/vue Warning]: The view you are trying to render for path ${currentRoute.pathname} does not have the required component. Transitions and lifecycle methods may not work as expected.
+
+See https://ionicframework.com/docs/vue/navigation#ionpage for more information.`);
+ }
}
if (!enteringViewItem.mount) {
diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts
index a7fb9212e4..89d64f0c1c 100644
--- a/packages/vue/src/index.ts
+++ b/packages/vue/src/index.ts
@@ -68,7 +68,32 @@ export {
BackButtonEvent,
// Swiper
- IonicSwiper
+ IonicSwiper,
+
+ SpinnerTypes,
+
+ ActionSheetOptions,
+ ActionSheetButton,
+
+ AlertOptions,
+ AlertInput,
+ AlertTextareaAttributes,
+ AlertInputAttributes,
+ AlertButton,
+
+ LoadingOptions,
+
+ ModalOptions,
+
+ PickerOptions,
+ PickerButton,
+ PickerColumn,
+ PickerColumnOption,
+
+ PopoverOptions,
+
+ ToastOptions,
+ ToastButton
} from '@ionic/core/components';
// Icons that are used by internal components