mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 17:42:15 +08:00
chore(): sync with main
This commit is contained in:
60
.github/ISSUE_TEMPLATE/bug_report.md
vendored
60
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,60 +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**
|
|
||||||
[ ] **5.x**
|
|
||||||
[ ] **6.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
56
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal 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: 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.
|
11
.github/ISSUE_TEMPLATE/cli.md
vendored
11
.github/ISSUE_TEMPLATE/cli.md
vendored
@ -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
10
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal 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.
|
11
.github/ISSUE_TEMPLATE/documentation.md
vendored
11
.github/ISSUE_TEMPLATE/documentation.md
vendored
@ -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).
|
|
39
.github/ISSUE_TEMPLATE/feature_request.md
vendored
39
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,39 +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) -->
|
|
||||||
[ ] **4.x**
|
|
||||||
[ ] **5.x**
|
|
||||||
[ ] **6.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. -->
|
|
43
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
43
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -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.
|
11
.github/ISSUE_TEMPLATE/support_question.md
vendored
11
.github/ISSUE_TEMPLATE/support_question.md
vendored
@ -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/
|
|
@ -46,4 +46,44 @@ export { IonicModule } from './ionic-module';
|
|||||||
export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core';
|
export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core';
|
||||||
|
|
||||||
// CORE TYPES
|
// 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';
|
||||||
|
@ -254,7 +254,7 @@ rules:
|
|||||||
- visibility
|
- visibility
|
||||||
- z-index
|
- z-index
|
||||||
|
|
||||||
property-blacklist:
|
property-disallowed-list:
|
||||||
- background-position
|
- background-position
|
||||||
- right
|
- right
|
||||||
- left
|
- left
|
||||||
|
@ -110,10 +110,16 @@
|
|||||||
text-align: $action-sheet-ios-text-align;
|
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 {
|
.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);
|
@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-size: $action-sheet-ios-sub-title-font-size;
|
||||||
|
|
||||||
|
font-weight: $action-sheet-ios-title-font-weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +55,9 @@ $action-sheet-ios-title-font-size: 13px !default;
|
|||||||
/// @prop - Font weight of the action sheet title
|
/// @prop - Font weight of the action sheet title
|
||||||
$action-sheet-ios-title-font-weight: 400 !default;
|
$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
|
/// @prop - Border width of the action sheet title
|
||||||
$action-sheet-ios-title-border-width: $hairlines-width !default;
|
$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
|
/// @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
|
/// @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
|
/// @prop - Padding end of the action sheet sub title
|
||||||
$action-sheet-ios-sub-title-padding-end: 0 !default;
|
$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;
|
$action-sheet-ios-button-icon-font-size: 28px !default;
|
||||||
|
|
||||||
/// @prop - Padding right of the action sheet button icon
|
/// @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
|
/// @prop - Font size of the action sheet button
|
||||||
$action-sheet-ios-button-font-size: 20px !default;
|
$action-sheet-ios-button-font-size: 20px !default;
|
||||||
|
@ -258,7 +258,10 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
|||||||
<div class="action-sheet-container">
|
<div class="action-sheet-container">
|
||||||
<div class="action-sheet-group" ref={el => this.groupEl = el}>
|
<div class="action-sheet-group" ref={el => this.groupEl = el}>
|
||||||
{this.header !== undefined &&
|
{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.header}
|
||||||
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
|
{this.subHeader && <div class="action-sheet-sub-title">{this.subHeader}</div>}
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,39 @@ 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.
|
> 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;
|
||||||
|
|
||||||
|
enterAnimation?: AnimationBuilder;
|
||||||
|
leaveAnimation?: AnimationBuilder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
@ -41,6 +41,76 @@ 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.
|
> 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?: 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;
|
||||||
|
|
||||||
|
mode?: Mode;
|
||||||
|
keyboardClose?: boolean;
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
enterAnimation?: AnimationBuilder;
|
||||||
|
leaveAnimation?: AnimationBuilder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### AlertTextareaAttributes
|
||||||
|
```typescript
|
||||||
|
interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
vertical-align: top; // the better option for most scenarios
|
vertical-align: top; // the better option for most scenarios
|
||||||
vertical-align: -webkit-baseline-middle; // the best for those that support it
|
vertical-align: -webkit-baseline-middle; // the best for those that support it
|
||||||
pointer-events: auto;
|
|
||||||
|
|
||||||
font-kerning: none;
|
font-kerning: none;
|
||||||
}
|
}
|
||||||
|
@ -146,9 +146,9 @@
|
|||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
left: -100%;
|
left: -100%;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@ -161,9 +161,9 @@
|
|||||||
.transition-cover {
|
.transition-cover {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: 0;
|
right: 0;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -177,9 +177,9 @@
|
|||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: 0;
|
right: 0;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
width: 10px;
|
width: 10px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
ion-item-options {
|
ion-item-options {
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
}
|
}
|
||||||
|
|
||||||
@include ltr() {
|
@include ltr() {
|
||||||
@ -19,10 +19,10 @@ ion-item-options {
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
&:not(.item-options-end) {
|
&:not(.item-options-end) {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
@ -41,10 +41,10 @@ ion-item-options {
|
|||||||
|
|
||||||
.item-options-start {
|
.item-options-start {
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
}
|
}
|
||||||
|
|
||||||
@include ltr() {
|
@include ltr() {
|
||||||
|
@ -32,7 +32,7 @@ ion-item-sliding .item {
|
|||||||
|
|
||||||
.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
|
.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
padding-left: 100%;
|
padding-left: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ ion-item-sliding .item {
|
|||||||
|
|
||||||
.item-sliding-active-swipe-start .item-options-start .item-option-expandable {
|
.item-sliding-active-swipe-start .item-options-start .item-option-expandable {
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
padding-right: 100%;
|
padding-right: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { counterString, detail, detailIcon, download, fill, labelColorStyles, lines, disabled, href, rel, shape, target, routerAnimation, routerDirection } = this;
|
const { counterString, detail, detailIcon, download, fill, labelColorStyles, lines, disabled, href, rel, shape, target, routerAnimation, routerDirection } = this;
|
||||||
const childStyles = {};
|
const childStyles = {} as any;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const clickable = this.isClickable();
|
const clickable = this.isClickable();
|
||||||
const canActivate = this.canActivate();
|
const canActivate = this.canActivate();
|
||||||
@ -322,10 +322,11 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
|||||||
this.itemStyles.forEach(value => {
|
this.itemStyles.forEach(value => {
|
||||||
Object.assign(childStyles, value);
|
Object.assign(childStyles, value);
|
||||||
});
|
});
|
||||||
|
const ariaDisabled = (disabled || childStyles['item-interactive-disabled']) ? 'true' : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
aria-disabled={disabled ? 'true' : null}
|
aria-disabled={ariaDisabled}
|
||||||
class={{
|
class={{
|
||||||
...childStyles,
|
...childStyles,
|
||||||
...labelColorStyles,
|
...labelColorStyles,
|
||||||
|
11
core/src/components/item/test/a11y/e2e.ts
Normal file
11
core/src/components/item/test/a11y/e2e.ts
Normal 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);
|
||||||
|
});
|
105
core/src/components/item/test/a11y/index.html
Normal file
105
core/src/components/item/test/a11y/index.html
Normal 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>
|
@ -37,6 +37,28 @@ 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.
|
> 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;
|
||||||
|
|
||||||
|
enterAnimation?: AnimationBuilder;
|
||||||
|
leaveAnimation?: AnimationBuilder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
@ -139,17 +161,23 @@ import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
|
|||||||
interface LoadingProps {}
|
interface LoadingProps {}
|
||||||
|
|
||||||
const LoadingExample: React.FC<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 (
|
return (
|
||||||
<IonPage>
|
<IonPage>
|
||||||
<IonContent>
|
<IonContent>
|
||||||
<IonButton
|
<IonButton
|
||||||
expand="block"
|
expand="block"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
present({
|
present({
|
||||||
duration: 3000,
|
message: 'Loading...',
|
||||||
|
duration: 3000
|
||||||
})
|
})
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
Show Loading
|
Show Loading
|
||||||
</IonButton>
|
</IonButton>
|
||||||
|
@ -7,17 +7,23 @@ import { IonButton, IonContent, IonPage, useIonLoading } from '@ionic/react';
|
|||||||
interface LoadingProps {}
|
interface LoadingProps {}
|
||||||
|
|
||||||
const LoadingExample: React.FC<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 (
|
return (
|
||||||
<IonPage>
|
<IonPage>
|
||||||
<IonContent>
|
<IonContent>
|
||||||
<IonButton
|
<IonButton
|
||||||
expand="block"
|
expand="block"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
present({
|
present({
|
||||||
duration: 3000,
|
message: 'Loading...',
|
||||||
|
duration: 3000
|
||||||
})
|
})
|
||||||
}
|
}}
|
||||||
>
|
>
|
||||||
Show Loading
|
Show Loading
|
||||||
</IonButton>
|
</IonButton>
|
||||||
|
@ -4,6 +4,7 @@ import { config } from '../../global/config';
|
|||||||
import { getIonMode } from '../../global/ionic-global';
|
import { getIonMode } from '../../global/ionic-global';
|
||||||
import { Color } from '../../interface';
|
import { Color } from '../../interface';
|
||||||
import { ButtonInterface } from '../../utils/element-interface';
|
import { ButtonInterface } from '../../utils/element-interface';
|
||||||
|
import { inheritAttributes } from '../../utils/helpers';
|
||||||
import { menuController } from '../../utils/menu-controller';
|
import { menuController } from '../../utils/menu-controller';
|
||||||
import { createColorClasses, hostContext } from '../../utils/theme';
|
import { createColorClasses, hostContext } from '../../utils/theme';
|
||||||
import { updateVisibility } from '../menu-toggle/menu-toggle-util';
|
import { updateVisibility } from '../menu-toggle/menu-toggle-util';
|
||||||
@ -23,6 +24,8 @@ import { updateVisibility } from '../menu-toggle/menu-toggle-util';
|
|||||||
shadow: true
|
shadow: true
|
||||||
})
|
})
|
||||||
export class MenuButton implements ComponentInterface, ButtonInterface {
|
export class MenuButton implements ComponentInterface, ButtonInterface {
|
||||||
|
private inheritedAttributes: { [k: string]: any } = {};
|
||||||
|
|
||||||
@Element() el!: HTMLIonSegmentElement;
|
@Element() el!: HTMLIonSegmentElement;
|
||||||
|
|
||||||
@State() visible = false;
|
@State() visible = false;
|
||||||
@ -54,6 +57,10 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
||||||
|
|
||||||
|
componentWillLoad() {
|
||||||
|
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
this.visibilityChanged();
|
this.visibilityChanged();
|
||||||
}
|
}
|
||||||
@ -69,7 +76,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { color, disabled } = this;
|
const { color, disabled, inheritedAttributes } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const menuIcon = config.get('menuIcon', mode === 'ios' ? 'menu-outline' : 'menu-sharp');
|
const menuIcon = config.get('menuIcon', mode === 'ios' ? 'menu-outline' : 'menu-sharp');
|
||||||
const hidden = this.autoHide && !this.visible;
|
const hidden = this.autoHide && !this.visible;
|
||||||
@ -78,6 +85,8 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
type: this.type
|
type: this.type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ariaLabel = inheritedAttributes['aria-label'] || 'menu';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
@ -99,7 +108,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
class="button-native"
|
class="button-native"
|
||||||
part="native"
|
part="native"
|
||||||
aria-label="menu"
|
aria-label={ariaLabel}
|
||||||
>
|
>
|
||||||
<span class="button-inner">
|
<span class="button-inner">
|
||||||
<slot>
|
<slot>
|
||||||
|
11
core/src/components/menu-button/test/a11y/e2e.ts
Normal file
11
core/src/components/menu-button/test/a11y/e2e.ts
Normal 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);
|
||||||
|
});
|
21
core/src/components/menu-button/test/a11y/index.html
Normal file
21
core/src/components/menu-button/test/a11y/index.html
Normal 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>
|
@ -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" 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-menu-button>
|
||||||
<ion-menu-button auto-hide="false" class="custom-large ion-focused"></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>
|
<h1>Colors</h1>
|
||||||
<ion-menu-button auto-hide="false" color="primary"></ion-menu-button>
|
<ion-menu-button auto-hide="false" color="primary"></ion-menu-button>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
--ion-safe-area-right: 0px;
|
--ion-safe-area-right: 0px;
|
||||||
|
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@
|
|||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
right: 0;
|
right: 0;
|
||||||
left: auto;
|
left: auto;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,30 @@ 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;
|
||||||
|
|
||||||
|
enterAnimation?: AnimationBuilder;
|
||||||
|
leaveAnimation?: AnimationBuilder;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
@ -549,6 +573,7 @@ In most scenarios, setting a ref on `IonRouterOutlet` and passing that ref's `cu
|
|||||||
isOpen={show2ndModal}
|
isOpen={show2ndModal}
|
||||||
cssClass='my-custom-class'
|
cssClass='my-custom-class'
|
||||||
presentingElement={firstModalRef.current}
|
presentingElement={firstModalRef.current}
|
||||||
|
swipeToClose={true}
|
||||||
onDidDismiss={() => setShow2ndModal(false)}>
|
onDidDismiss={() => setShow2ndModal(false)}>
|
||||||
<p>This is more modal content</p>
|
<p>This is more modal content</p>
|
||||||
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
|
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
|
||||||
@ -811,6 +836,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.
|
> 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
|
## Properties
|
||||||
|
@ -147,6 +147,7 @@ In most scenarios, setting a ref on `IonRouterOutlet` and passing that ref's `cu
|
|||||||
isOpen={show2ndModal}
|
isOpen={show2ndModal}
|
||||||
cssClass='my-custom-class'
|
cssClass='my-custom-class'
|
||||||
presentingElement={firstModalRef.current}
|
presentingElement={firstModalRef.current}
|
||||||
|
swipeToClose={true}
|
||||||
onDidDismiss={() => setShow2ndModal(false)}>
|
onDidDismiss={() => setShow2ndModal(false)}>
|
||||||
<p>This is more modal content</p>
|
<p>This is more modal content</p>
|
||||||
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
|
<IonButton onClick={() => setShow2ndModal(false)}>Close Modal</IonButton>
|
||||||
|
@ -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.
|
> 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>
|
||||||
|
```
|
@ -169,7 +169,7 @@ describe('NavController', () => {
|
|||||||
|
|
||||||
describe('insert', () => {
|
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 view4 = mockView(MockView4);
|
||||||
const instance4 = spyOnLifecycles(view4);
|
const instance4 = spyOnLifecycles(view4);
|
||||||
const opts: NavOptions = {};
|
const opts: NavOptions = {};
|
||||||
|
@ -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.
|
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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
@ -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.
|
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
|
## 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.
|
> 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
|
## Accessibility
|
||||||
|
|
||||||
### Keyboard Navigation
|
### Keyboard Navigation
|
||||||
|
@ -46,10 +46,10 @@
|
|||||||
|
|
||||||
// Extend a bit to overflow. The size of animated distance.
|
// Extend a bit to overflow. The size of animated distance.
|
||||||
.buffer-circles {
|
.buffer-circles {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
right: -10px;
|
right: -10px;
|
||||||
left: -10px;
|
left: -10px;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determinate progress bar
|
// Determinate progress bar
|
||||||
@ -58,7 +58,7 @@
|
|||||||
.progress,
|
.progress,
|
||||||
.progress-buffer-bar,
|
.progress-buffer-bar,
|
||||||
.buffer-circles-container {
|
.buffer-circles-container {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
transform-origin: left top;
|
transform-origin: left top;
|
||||||
|
|
||||||
transition: transform 150ms linear;
|
transition: transform 150ms linear;
|
||||||
@ -88,12 +88,12 @@
|
|||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
.indeterminate-bar-primary {
|
.indeterminate-bar-primary {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: -145.166611%;
|
left: -145.166611%;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
animation: primary-indeterminate-translate 2s infinite linear;
|
animation: primary-indeterminate-translate 2s infinite linear;
|
||||||
|
|
||||||
@ -104,12 +104,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.indeterminate-bar-secondary {
|
.indeterminate-bar-secondary {
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: -54.888891%;
|
left: -54.888891%;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
animation: secondary-indeterminate-translate 2s infinite linear;
|
animation: secondary-indeterminate-translate 2s infinite linear;
|
||||||
|
|
||||||
@ -125,11 +125,11 @@
|
|||||||
.buffer-circles {
|
.buffer-circles {
|
||||||
background-image: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%);
|
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-repeat: repeat-x;
|
||||||
background-position: 5px center;
|
background-position: 5px center;
|
||||||
background-size: 10px 10px;
|
background-size: 10px 10px;
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
animation: buffering 450ms infinite linear;
|
animation: buffering 450ms infinite linear;
|
||||||
|
@ -105,12 +105,12 @@
|
|||||||
@include margin-horizontal(-13px, null);
|
@include margin-horizontal(-13px, null);
|
||||||
|
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
border-radius: 50% 50% 50% 0;
|
border-radius: 50% 50% 50% 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include rtl() {
|
@include rtl() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
left: unset;
|
left: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
@include rtl() {
|
@include rtl() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
left: unset;
|
left: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@
|
|||||||
@include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0);
|
@include position(calc((var(--height) - var(--bar-height)) / 2), null, null, 0);
|
||||||
|
|
||||||
@include rtl() {
|
@include rtl() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
left: unset;
|
left: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
@include rtl() {
|
@include rtl() {
|
||||||
/* stylelint-disable-next-line property-blacklist */
|
/* stylelint-disable-next-line property-disallowed-list */
|
||||||
left: unset;
|
left: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# ion-router-outlet
|
# 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.
|
Although router outlet has methods for navigating around, it's recommended to use the navigation methods in your framework's router.
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
|||||||
private waitPromise?: Promise<void>;
|
private waitPromise?: Promise<void>;
|
||||||
private gesture?: Gesture;
|
private gesture?: Gesture;
|
||||||
private ani?: Animation;
|
private ani?: Animation;
|
||||||
private animationEnabled = true;
|
private gestureOrAnimationInProgress = false;
|
||||||
|
|
||||||
@Element() el!: HTMLElement;
|
@Element() el!: HTMLElement;
|
||||||
|
|
||||||
@ -61,17 +61,22 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
|||||||
@Event({ bubbles: false }) ionNavDidChange!: EventEmitter<void>;
|
@Event({ bubbles: false }) ionNavDidChange!: EventEmitter<void>;
|
||||||
|
|
||||||
async connectedCallback() {
|
async connectedCallback() {
|
||||||
|
const onStart = () => {
|
||||||
|
this.gestureOrAnimationInProgress = true;
|
||||||
|
if (this.swipeHandler) {
|
||||||
|
this.swipeHandler.onStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.gesture = (await import('../../utils/gesture/swipe-back')).createSwipeBackGesture(
|
this.gesture = (await import('../../utils/gesture/swipe-back')).createSwipeBackGesture(
|
||||||
this.el,
|
this.el,
|
||||||
() => !!this.swipeHandler && this.swipeHandler.canStart() && this.animationEnabled,
|
() => !this.gestureOrAnimationInProgress && !!this.swipeHandler && this.swipeHandler.canStart(),
|
||||||
() => this.swipeHandler && this.swipeHandler.onStart(),
|
() => onStart(),
|
||||||
step => this.ani && this.ani.progressStep(step),
|
step => this.ani && this.ani.progressStep(step),
|
||||||
(shouldComplete, step, dur) => {
|
(shouldComplete, step, dur) => {
|
||||||
if (this.ani) {
|
if (this.ani) {
|
||||||
this.animationEnabled = false;
|
|
||||||
|
|
||||||
this.ani.onFinish(() => {
|
this.ani.onFinish(() => {
|
||||||
this.animationEnabled = true;
|
this.gestureOrAnimationInProgress = false;
|
||||||
|
|
||||||
if (this.swipeHandler) {
|
if (this.swipeHandler) {
|
||||||
this.swipeHandler.onEnd(shouldComplete);
|
this.swipeHandler.onEnd(shouldComplete);
|
||||||
@ -97,7 +102,8 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
|
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
|
||||||
|
} else {
|
||||||
|
this.gestureOrAnimationInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -191,7 +197,34 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
|||||||
leavingEl,
|
leavingEl,
|
||||||
baseEl: el,
|
baseEl: el,
|
||||||
progressCallback: (opts.progressAnimation
|
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
|
: undefined
|
||||||
),
|
),
|
||||||
...opts,
|
...opts,
|
||||||
|
@ -61,7 +61,7 @@ span {
|
|||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stylelint-disable property-blacklist */
|
/* stylelint-disable property-disallowed-list */
|
||||||
@keyframes shimmer {
|
@keyframes shimmer {
|
||||||
0% {
|
0% {
|
||||||
background-position: -400px 0;
|
background-position: -400px 0;
|
||||||
@ -71,4 +71,4 @@ span {
|
|||||||
background-position: 400px 0;
|
background-position: 400px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* stylelint-enable property-blacklist */
|
/* stylelint-enable property-disallowed-list */
|
||||||
|
@ -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.
|
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<boolean | void>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ ion-virtual-scroll > .virtual-loading {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ion-virtual-scroll > .virtual-item {
|
ion-virtual-scroll > .virtual-item {
|
||||||
/* stylelint-disable declaration-no-important, property-blacklist */
|
/* stylelint-disable declaration-no-important, property-disallowed-list */
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
|
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
|
@ -10,6 +10,7 @@ describe('Swipe To Go Back', () => {
|
|||||||
cy.ionPageVisible('main');
|
cy.ionPageVisible('main');
|
||||||
cy.ionNav('ion-item', 'Details');
|
cy.ionNav('ion-item', 'Details');
|
||||||
cy.ionPageVisible('details');
|
cy.ionPageVisible('details');
|
||||||
|
cy.ionPageHidden('main');
|
||||||
cy.ionSwipeToGoBack(true);
|
cy.ionSwipeToGoBack(true);
|
||||||
cy.ionPageVisible('main');
|
cy.ionPageVisible('main');
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
These are React specific building blocks on top of [@ionic/core](https://www.npmjs.com/package/@ionic/core) components/services.
|
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
|
# Current Status of Components
|
||||||
|
|
||||||
|
@ -26,8 +26,6 @@ export {
|
|||||||
AnimationLifecycle,
|
AnimationLifecycle,
|
||||||
createAnimation,
|
createAnimation,
|
||||||
createGesture,
|
createGesture,
|
||||||
AlertButton,
|
|
||||||
AlertInput,
|
|
||||||
Gesture,
|
Gesture,
|
||||||
GestureConfig,
|
GestureConfig,
|
||||||
GestureDetail,
|
GestureDetail,
|
||||||
@ -36,7 +34,33 @@ export {
|
|||||||
mdTransitionAnimation,
|
mdTransitionAnimation,
|
||||||
NavComponentWithProps,
|
NavComponentWithProps,
|
||||||
setupConfig,
|
setupConfig,
|
||||||
|
|
||||||
IonicSwiper,
|
IonicSwiper,
|
||||||
|
|
||||||
|
SpinnerTypes,
|
||||||
|
|
||||||
|
ActionSheetOptions,
|
||||||
|
ActionSheetButton,
|
||||||
|
|
||||||
|
AlertOptions,
|
||||||
|
AlertInput,
|
||||||
|
AlertTextareaAttributes,
|
||||||
|
AlertInputAttributes,
|
||||||
|
AlertButton,
|
||||||
|
|
||||||
|
LoadingOptions,
|
||||||
|
|
||||||
|
ModalOptions,
|
||||||
|
|
||||||
|
PickerOptions,
|
||||||
|
PickerButton,
|
||||||
|
PickerColumn,
|
||||||
|
PickerColumnOption,
|
||||||
|
|
||||||
|
PopoverOptions,
|
||||||
|
|
||||||
|
ToastOptions,
|
||||||
|
ToastButton
|
||||||
} from '@ionic/core';
|
} from '@ionic/core';
|
||||||
export * from './proxies';
|
export * from './proxies';
|
||||||
|
|
||||||
|
@ -311,6 +311,17 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
|
|||||||
if (!enteringViewItem) {
|
if (!enteringViewItem) {
|
||||||
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
|
enteringViewItem = viewStacks.createViewItem(id, matchedRouteRef.value.components.default, matchedRouteRef.value, currentRoute);
|
||||||
viewStacks.add(enteringViewItem);
|
viewStacks.add(enteringViewItem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All views that can be transitioned to must have
|
||||||
|
* an `<ion-page>` 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 <ion-page> component. Transitions and lifecycle methods may not work as expected.
|
||||||
|
|
||||||
|
See https://ionicframework.com/docs/vue/navigation#ionpage for more information.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enteringViewItem.mount) {
|
if (!enteringViewItem.mount) {
|
||||||
|
@ -68,7 +68,32 @@ export {
|
|||||||
BackButtonEvent,
|
BackButtonEvent,
|
||||||
|
|
||||||
// Swiper
|
// Swiper
|
||||||
IonicSwiper
|
IonicSwiper,
|
||||||
|
|
||||||
|
SpinnerTypes,
|
||||||
|
|
||||||
|
ActionSheetOptions,
|
||||||
|
ActionSheetButton,
|
||||||
|
|
||||||
|
AlertOptions,
|
||||||
|
AlertInput,
|
||||||
|
AlertTextareaAttributes,
|
||||||
|
AlertInputAttributes,
|
||||||
|
AlertButton,
|
||||||
|
|
||||||
|
LoadingOptions,
|
||||||
|
|
||||||
|
ModalOptions,
|
||||||
|
|
||||||
|
PickerOptions,
|
||||||
|
PickerButton,
|
||||||
|
PickerColumn,
|
||||||
|
PickerColumnOption,
|
||||||
|
|
||||||
|
PopoverOptions,
|
||||||
|
|
||||||
|
ToastOptions,
|
||||||
|
ToastButton
|
||||||
} from '@ionic/core/components';
|
} from '@ionic/core/components';
|
||||||
|
|
||||||
// Icons that are used by internal components
|
// Icons that are used by internal components
|
||||||
|
Reference in New Issue
Block a user