mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8445d7b515 | ||
|
|
1decc13cb8 | ||
|
|
17308f247f | ||
|
|
d8b377ffeb | ||
|
|
24cfdc308f | ||
|
|
bcccc217b8 | ||
|
|
e968bd029a | ||
|
|
7c8f621536 | ||
|
|
edceac0745 | ||
|
|
2969f9f9f2 | ||
|
|
9223abc1f8 | ||
|
|
b37c158eea | ||
|
|
ce6448b068 | ||
|
|
fd65ceec84 | ||
|
|
0bf9449ee1 | ||
|
|
cf3035778c | ||
|
|
17375d2325 | ||
|
|
df408f91f1 | ||
|
|
e95b481a53 | ||
|
|
698e526b9f | ||
|
|
f34d3752e3 | ||
|
|
c8db0d5eeb | ||
|
|
a4f0bdb4c3 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -19,7 +19,8 @@ assignees: ''
|
||||
**Ionic version:**
|
||||
<!-- (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1) -->
|
||||
<!-- (For Ionic 2.x & 3.x issues, please use https://github.com/ionic-team/ionic-v3) -->
|
||||
[x] **4.x**
|
||||
[ ] **4.x**
|
||||
[x] **5.x**
|
||||
|
||||
**Current behavior:**
|
||||
<!-- Describe how the bug manifests. -->
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,3 +1,64 @@
|
||||
## [5.2.2](https://github.com/ionic-team/ionic/compare/v5.2.1...v5.2.2) (2020-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **action-sheet, alert:** resolve double click issue when running in iOS mode on chrome ([#21506](https://github.com/ionic-team/ionic/issues/21506)) ([bcccc21](https://github.com/ionic-team/ionic/commit/bcccc217b8833a284a1781e287db5e46043b3548)), closes [#21503](https://github.com/ionic-team/ionic/issues/21503)
|
||||
* **angular:** fix issue where navAnimation was being incorrectly overridden ([#21508](https://github.com/ionic-team/ionic/issues/21508)) ([e968bd0](https://github.com/ionic-team/ionic/commit/e968bd029a4fb37b4001d96a490c6091a948785a)), closes [#21495](https://github.com/ionic-team/ionic/issues/21495)
|
||||
* **input:** add aria-label to clear button ([#21538](https://github.com/ionic-team/ionic/issues/21538)) ([d8b377f](https://github.com/ionic-team/ionic/commit/d8b377ffeb88eaae23b33eadeae5c8e54e1bc77c)), closes [#21537](https://github.com/ionic-team/ionic/issues/21537)
|
||||
* **ios:** respect toolbar opacity when doing nav transition ([#21512](https://github.com/ionic-team/ionic/issues/21512)) ([24cfdc3](https://github.com/ionic-team/ionic/commit/24cfdc308f63b7a55969ac58806eafd67116b017))
|
||||
* **segment:** ensure checked classes get set after not having a value ([#21547](https://github.com/ionic-team/ionic/issues/21547)) ([17308f2](https://github.com/ionic-team/ionic/commit/17308f247f8750029ece39548c9f457e15326189)), closes [#21546](https://github.com/ionic-team/ionic/issues/21546)
|
||||
|
||||
|
||||
## [5.2.1](https://github.com/ionic-team/ionic/compare/v5.2.0...v5.2.1) (2020-06-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** resolve error when not using ngModel on components ([4083e32](https://github.com/ionic-team/ionic/commit/4083e32e103db71f6db86ed1ecd398fda407c28b))
|
||||
|
||||
|
||||
|
||||
# [5.2.0 Silicon](https://github.com/ionic-team/ionic/compare/v5.1.1...v5.2.0) (2020-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **action-sheet, toast:** allow button handler to return `Promise<void>` ([#21259](https://github.com/ionic-team/ionic/issues/21259)) ([7703da2](https://github.com/ionic-team/ionic/commit/7703da28f8181b02390b97a7d4d02df99b2ad34c))
|
||||
* **angular:** patch FormControl methods to properly sync Ionic form classes ([#21429](https://github.com/ionic-team/ionic/issues/21429)) ([e95b481](https://github.com/ionic-team/ionic/commit/e95b481a53191582bca635f322ad07eadbd62d64))
|
||||
* **datetime:** ensure year-only values are not affected by timezone when parsing ([#21309](https://github.com/ionic-team/ionic/issues/21309)) ([3937101](https://github.com/ionic-team/ionic/commit/3937101e5c2b181a6b7926eb8386c22b0f887716))
|
||||
* **header:** large title transition now works on older versions of iOS ([#21339](https://github.com/ionic-team/ionic/issues/21339)) ([2dac12c](https://github.com/ionic-team/ionic/commit/2dac12c577e0c7a5310857389dbda2b2b3dfadd1))
|
||||
* **img:** use setTimeout fallback on older versions of chrome ([#21358](https://github.com/ionic-team/ionic/issues/21358)) ([0bf9449](https://github.com/ionic-team/ionic/commit/0bf9449ee1f9b2498e35f61511cb3e018814c6ca))
|
||||
* **ios:** add haptic drag gesture for action sheet and alert components ([#21060](https://github.com/ionic-team/ionic/issues/21060)) ([33be1f0](https://github.com/ionic-team/ionic/commit/33be1f061ebbe27ee22e357c394f112af42ec360))
|
||||
* **item:** inherit align-items from parent item ([#19278](https://github.com/ionic-team/ionic/issues/19278)) ([882f8fe](https://github.com/ionic-team/ionic/commit/882f8fef07dfb6ebda17ca09046d1af281075098)), closes [#18703](https://github.com/ionic-team/ionic/issues/18703)
|
||||
* **item:** input-wrapper now inherits overflow ([#21282](https://github.com/ionic-team/ionic/issues/21282)) ([29d208d](https://github.com/ionic-team/ionic/commit/29d208de88f340e216e22badb6366bba4eda8bfb))
|
||||
* **menu-button:** screen readers now properly announce menu button ([#21324](https://github.com/ionic-team/ionic/issues/21324)) ([eaf4fb6](https://github.com/ionic-team/ionic/commit/eaf4fb6b2a6d68f5c3d8d49ef41b4885f096070d))
|
||||
* **modal:** card style modal no longer gets stuck when swiping quickly ([#21224](https://github.com/ionic-team/ionic/issues/21224)) ([448dfa0](https://github.com/ionic-team/ionic/commit/448dfa0a6955008ce4dc73354f5b8319ae1a1cc2))
|
||||
* **modal:** set card-style modal height using the --height css variable ([#21453](https://github.com/ionic-team/ionic/issues/21453)) ([a4f0bdb](https://github.com/ionic-team/ionic/commit/a4f0bdb4c3ceeeaf902d520e9aa72e04a6ec2302))
|
||||
* **reorder-group:** revert item to original position when passing false to complete ([#21396](https://github.com/ionic-team/ionic/issues/21396)) ([5f2001c](https://github.com/ionic-team/ionic/commit/5f2001c43c0846ec8973cbb8eb5662976ba7e31a)), closes [#19128](https://github.com/ionic-team/ionic/issues/19128)
|
||||
* **router:** use correct nav transition when going back ([#21301](https://github.com/ionic-team/ionic/issues/21301)) ([c8db0d5](https://github.com/ionic-team/ionic/commit/c8db0d5eeba6f10d1492e95e6df6b4d871d43400))
|
||||
* **scroll-assist:** improve scroll detection accuracy ([#21416](https://github.com/ionic-team/ionic/issues/21416)) ([137c49d](https://github.com/ionic-team/ionic/commit/137c49d70be45e1b0ee73d41fed6e9d69a2caa32))
|
||||
* **slides:** update Swiper dependency to resolve error when doing SSR ([#21350](https://github.com/ionic-team/ionic/issues/21350)) ([3290604](https://github.com/ionic-team/ionic/commit/32906048a491961ec7340ba2e085807ea8a9c118))
|
||||
* **textarea:** native textarea inherits max/min width and height ([#21333](https://github.com/ionic-team/ionic/issues/21333)) ([2377480](https://github.com/ionic-team/ionic/commit/237748049c7644ae8a7a74101ece5cfd7a160470))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **alert:** add destructive role to alert buttons ([#21269](https://github.com/ionic-team/ionic/issues/21269)) ([e53f024](https://github.com/ionic-team/ionic/commit/e53f0241e2bf91461c55097fde271ae85ca644ea))
|
||||
* **alert:** add support for custom input attributes ([#21365](https://github.com/ionic-team/ionic/issues/21365)) ([1ed8169](https://github.com/ionic-team/ionic/commit/1ed81693f225b6801a0897ef1a8314999c122484))
|
||||
* **all:** add all autocomplete values to input and searchbar ([#21297](https://github.com/ionic-team/ionic/issues/21297)) ([4fd7c0c](https://github.com/ionic-team/ionic/commit/4fd7c0cc5a6c97100fa380e4ff1be0bb84c7006b))
|
||||
* **all:** add optional generic typings for overlay component methods ([#21393](https://github.com/ionic-team/ionic/issues/21393)) ([5bf83b8](https://github.com/ionic-team/ionic/commit/5bf83b80d7d2749719dd1a280ae8e205fbc4b2a9))
|
||||
* **all:** add shadow parts to missing components ([#21436](https://github.com/ionic-team/ionic/issues/21436)) ([17375d2](https://github.com/ionic-team/ionic/commit/17375d232500b47ef1cacd7c028c38990d307984))
|
||||
* **all:** add support for configuring animations on a per-page basis ([#21433](https://github.com/ionic-team/ionic/issues/21433)) ([f34d375](https://github.com/ionic-team/ionic/commit/f34d3752e3462c9d81487fc86af5ec185cc3d1e3))
|
||||
* **angular:** expose activatedView ([#21302](https://github.com/ionic-team/ionic/issues/21302)) ([829a0d9](https://github.com/ionic-team/ionic/commit/829a0d9be5a20c5fc96b5c5f18fedc4eb5e5b9ec))
|
||||
* **angular:** expose getPlatforms and isPlatform ([#21308](https://github.com/ionic-team/ionic/issues/21308)) ([4af54a2](https://github.com/ionic-team/ionic/commit/4af54a2fea5d9cef843b1ebce849fb4a5c206f0b))
|
||||
* **angular:** add strongly typed Ionic lifecycle hooks ([#18044](https://github.com/ionic-team/ionic/issues/18044)) ([53fc8e3](https://github.com/ionic-team/ionic/commit/53fc8e37c89cea793d0e00246d52805166730108)), closes [#18043](https://github.com/ionic-team/ionic/issues/18043)
|
||||
* **fab-button:** add close icon font size css variable ([#19628](https://github.com/ionic-team/ionic/issues/19628)) ([df408f9](https://github.com/ionic-team/ionic/commit/df408f91f1aef903adaa5e635fef9bc7542e8739))
|
||||
* **fab-button:** add closeIcon property ([#19626](https://github.com/ionic-team/ionic/issues/19626)) ([698e526](https://github.com/ionic-team/ionic/commit/698e526b9f882e98efc4bf160999182c645b772c))
|
||||
* **select-option:** pass class from the option to the interface for individual styling ([#21304](https://github.com/ionic-team/ionic/issues/21304)) ([5285824](https://github.com/ionic-team/ionic/commit/5285824da5258ea638420fc60c50e0a19952f89c))
|
||||
|
||||
|
||||
|
||||
## [5.1.1](https://github.com/ionic-team/ionic/compare/v5.1.0...v5.1.1) (2020-05-13)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -42,7 +42,7 @@
|
||||
"validate": "npm i && npm run lint && npm run test && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "5.1.1",
|
||||
"@ionic/core": "5.2.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor, setIonicClasses } from './value-accessor';
|
||||
@@ -16,8 +16,8 @@ import { ValueAccessor, setIonicClasses } from './value-accessor';
|
||||
})
|
||||
export class BooleanValueAccessor extends ValueAccessor {
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
super(el);
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
writeValue(value: any) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
|
||||
})
|
||||
export class NumericValueAccessor extends ValueAccessor {
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
super(el);
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
|
||||
})
|
||||
export class RadioValueAccessor extends ValueAccessor {
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
super(el);
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionSelect', ['$event.target'])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
|
||||
})
|
||||
export class SelectValueAccessor extends ValueAccessor {
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
super(el);
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@@ -16,8 +16,8 @@ import { ValueAccessor } from './value-accessor';
|
||||
})
|
||||
export class TextValueAccessor extends ValueAccessor {
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
super(el);
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { ElementRef, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor } from '@angular/forms';
|
||||
import { AfterViewInit, ElementRef, HostListener, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { ControlValueAccessor, NgControl } from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { raf } from '../../util/util';
|
||||
|
||||
export class ValueAccessor implements ControlValueAccessor {
|
||||
export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDestroy {
|
||||
|
||||
private onChange: (value: any) => void = () => {/**/};
|
||||
private onTouched: () => void = () => {/**/};
|
||||
protected lastValue: any;
|
||||
private statusChanges?: Subscription;
|
||||
|
||||
constructor(protected el: ElementRef) {}
|
||||
constructor(protected injector: Injector, protected el: ElementRef) {}
|
||||
|
||||
writeValue(value: any) {
|
||||
/**
|
||||
@@ -52,6 +54,50 @@ export class ValueAccessor implements ControlValueAccessor {
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
this.el.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.statusChanges) {
|
||||
this.statusChanges.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
let ngControl;
|
||||
try {
|
||||
ngControl = this.injector.get<NgControl>(NgControl as Type<NgControl>);
|
||||
} catch { /* No FormControl or ngModel binding */ }
|
||||
|
||||
if (!ngControl) { return; }
|
||||
|
||||
// Listen for changes in validity, disabled, or pending states
|
||||
if (ngControl.statusChanges) {
|
||||
this.statusChanges = ngControl.statusChanges.subscribe(() => setIonicClasses(this.el));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Remove this in favor of https://github.com/angular/angular/issues/10887
|
||||
* whenever it is implemented. Currently, Ionic's form status classes
|
||||
* do not react to changes when developers manually call
|
||||
* Angular form control methods such as markAsTouched.
|
||||
* This results in Ionic's form status classes being out
|
||||
* of sync with the ng form status classes.
|
||||
* This patches the methods to manually sync
|
||||
* the classes until this feature is implemented in Angular.
|
||||
*/
|
||||
const formControl = ngControl.control;
|
||||
if (formControl) {
|
||||
const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine'];
|
||||
methodsToPatch.forEach(method => {
|
||||
if (formControl[method]) {
|
||||
const oldFn = formControl[method].bind(formControl);
|
||||
formControl[method] = (...params) => {
|
||||
oldFn(...params);
|
||||
setIonicClasses(this.el);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const setIonicClasses = (element: ElementRef) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Directive, HostListener, Optional } from '@angular/core';
|
||||
import { AnimationBuilder } from '@ionic/core';
|
||||
|
||||
import { Config } from '../../providers/config';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
@@ -7,11 +8,12 @@ import { IonRouterOutlet } from './ion-router-outlet';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-back-button',
|
||||
inputs: ['defaultHref'],
|
||||
inputs: ['defaultHref', 'routerAnimation'],
|
||||
})
|
||||
export class IonBackButtonDelegate {
|
||||
|
||||
defaultHref: string | undefined | null;
|
||||
routerAnimation?: AnimationBuilder;
|
||||
|
||||
constructor(
|
||||
@Optional() private routerOutlet: IonRouterOutlet,
|
||||
@@ -27,10 +29,11 @@ export class IonBackButtonDelegate {
|
||||
const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');
|
||||
|
||||
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
|
||||
this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation);
|
||||
this.routerOutlet.pop();
|
||||
ev.preventDefault();
|
||||
} else if (defaultHref != null) {
|
||||
this.navCtrl.navigateBack(defaultHref);
|
||||
this.navCtrl.navigateBack(defaultHref, { animation: this.routerAnimation });
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { LocationStrategy } from '@angular/common';
|
||||
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { RouterDirection } from '@ionic/core';
|
||||
import { AnimationBuilder, RouterDirection } from '@ionic/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
@Directive({
|
||||
selector: '[routerLink]',
|
||||
inputs: ['routerDirection']
|
||||
inputs: ['routerDirection', 'routerAnimation']
|
||||
})
|
||||
export class RouterLinkDelegate {
|
||||
|
||||
private subscription?: Subscription;
|
||||
|
||||
routerDirection: RouterDirection = 'forward';
|
||||
routerAnimation?: AnimationBuilder;
|
||||
|
||||
constructor(
|
||||
private locationStrategy: LocationStrategy,
|
||||
@@ -50,7 +51,7 @@ export class RouterLinkDelegate {
|
||||
*/
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(ev: UIEvent) {
|
||||
this.navCtrl.setDirection(this.routerDirection);
|
||||
this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation);
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { ComponentRef, NgZone } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouterDirection } from '@ionic/core';
|
||||
import { AnimationBuilder, RouterDirection } from '@ionic/core';
|
||||
|
||||
import { bindLifecycleEvents } from '../../providers/angular-delegate';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
@@ -52,7 +52,8 @@ export class StackController {
|
||||
}
|
||||
|
||||
setActive(enteringView: RouteView): Promise<StackEvent> {
|
||||
let { direction, animation } = this.navCtrl.consumeTransition();
|
||||
const consumeResult = this.navCtrl.consumeTransition();
|
||||
let { direction, animation, animationBuilder } = consumeResult;
|
||||
const leavingView = this.activeView;
|
||||
const tabSwitch = isTabSwitch(enteringView, leavingView);
|
||||
if (tabSwitch) {
|
||||
@@ -105,6 +106,31 @@ export class StackController {
|
||||
enteringView.ref.changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are going back from a page that
|
||||
* was presented using a custom animation
|
||||
* we should default to using that
|
||||
* unless the developer explicitly
|
||||
* provided another animation.
|
||||
*/
|
||||
const customAnimation = enteringView.animationBuilder;
|
||||
if (
|
||||
animationBuilder === undefined &&
|
||||
direction === 'back' &&
|
||||
!tabSwitch &&
|
||||
customAnimation !== undefined
|
||||
) {
|
||||
animationBuilder = customAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save any custom animation so that navigating
|
||||
* back will use this custom animation by default.
|
||||
*/
|
||||
if (animationBuilder !== undefined && leavingView) {
|
||||
leavingView.animationBuilder = animationBuilder;
|
||||
}
|
||||
|
||||
// Wait until previous transitions finish
|
||||
return this.zone.runOutsideAngular(() => {
|
||||
return this.wait(() => {
|
||||
@@ -116,7 +142,7 @@ export class StackController {
|
||||
// In case the enteringView is the same as the leavingPage we need to reattach()
|
||||
enteringView.ref.changeDetectorRef.reattach();
|
||||
|
||||
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
|
||||
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false, animationBuilder)
|
||||
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
|
||||
.then(() => ({
|
||||
enteringView,
|
||||
@@ -154,8 +180,8 @@ export class StackController {
|
||||
url = primaryOutlet.route._routerState.snapshot.url;
|
||||
}
|
||||
}
|
||||
|
||||
return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true);
|
||||
const { animationBuilder } = this.navCtrl.consumeTransition();
|
||||
return this.navCtrl.navigateBack(url, { ...view.savedExtras, animation: animationBuilder }).then(() => true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -225,7 +251,8 @@ export class StackController {
|
||||
leavingView: RouteView | undefined,
|
||||
direction: 'forward' | 'back' | undefined,
|
||||
showGoBack: boolean,
|
||||
progressAnimation: boolean
|
||||
progressAnimation: boolean,
|
||||
animationBuilder?: AnimationBuilder
|
||||
) {
|
||||
if (this.skipTransition) {
|
||||
this.skipTransition = false;
|
||||
@@ -250,7 +277,8 @@ export class StackController {
|
||||
duration: direction === undefined ? 0 : undefined,
|
||||
direction,
|
||||
showGoBack,
|
||||
progressAnimation
|
||||
progressAnimation,
|
||||
animationBuilder
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ComponentRef } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
||||
import { NavDirection, RouterDirection } from '@ionic/core';
|
||||
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
|
||||
if (direction === 'root') {
|
||||
@@ -96,4 +96,5 @@ export interface RouteView {
|
||||
savedData?: any;
|
||||
savedExtras?: NavigationExtras;
|
||||
unlistenEvents: () => void;
|
||||
animationBuilder?: AnimationBuilder;
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ export class IonAvatar {
|
||||
}
|
||||
export declare interface IonBackButton extends Components.IonBackButton {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] })
|
||||
@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] })
|
||||
@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] })
|
||||
@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] })
|
||||
export class IonBackButton {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
@@ -61,8 +61,8 @@ export class IonBadge {
|
||||
}
|
||||
export declare interface IonButton extends Components.IonButton {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] })
|
||||
@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] })
|
||||
@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] })
|
||||
@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] })
|
||||
export class IonButton {
|
||||
ionFocus!: EventEmitter<CustomEvent>;
|
||||
ionBlur!: EventEmitter<CustomEvent>;
|
||||
@@ -86,8 +86,8 @@ export class IonButtons {
|
||||
}
|
||||
export declare interface IonCard extends Components.IonCard {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] })
|
||||
@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] })
|
||||
@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
|
||||
@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
|
||||
export class IonCard {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
@@ -220,8 +220,8 @@ export class IonFab {
|
||||
}
|
||||
export declare interface IonFabButton extends Components.IonFabButton {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] })
|
||||
@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] })
|
||||
@ProxyCmp({ inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] })
|
||||
@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] })
|
||||
export class IonFabButton {
|
||||
ionFocus!: EventEmitter<CustomEvent>;
|
||||
ionBlur!: EventEmitter<CustomEvent>;
|
||||
@@ -344,8 +344,8 @@ export class IonInput {
|
||||
}
|
||||
export declare interface IonItem extends Components.IonItem {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] })
|
||||
@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] })
|
||||
@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
|
||||
@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
|
||||
export class IonItem {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
@@ -462,8 +462,8 @@ export class IonMenu {
|
||||
}
|
||||
export declare interface IonMenuButton extends Components.IonMenuButton {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["autoHide", "color", "disabled", "menu", "type"] })
|
||||
@Component({ selector: "ion-menu-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["autoHide", "color", "disabled", "menu", "type"] })
|
||||
@ProxyCmp({ inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] })
|
||||
@Component({ selector: "ion-menu-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["autoHide", "color", "disabled", "menu", "mode", "type"] })
|
||||
export class IonMenuButton {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
@@ -498,8 +498,8 @@ export class IonNav {
|
||||
}
|
||||
export declare interface IonNavLink extends Components.IonNavLink {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["component", "componentProps", "routerDirection"] })
|
||||
@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["component", "componentProps", "routerDirection"] })
|
||||
@ProxyCmp({ inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] })
|
||||
@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] })
|
||||
export class IonNavLink {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
|
||||
import { NavDirection, RouterDirection } from '@ionic/core';
|
||||
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Platform } from './platform';
|
||||
|
||||
export interface AnimationOptions {
|
||||
animated?: boolean;
|
||||
animation?: AnimationBuilder;
|
||||
animationDirection?: 'forward' | 'back';
|
||||
}
|
||||
|
||||
@@ -22,6 +23,7 @@ export class NavController {
|
||||
private topOutlet?: IonRouterOutlet;
|
||||
private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
|
||||
private animated?: NavDirection = DEFAULT_ANIMATED;
|
||||
private animationBuilder?: AnimationBuilder;
|
||||
private guessDirection: RouterDirection = 'forward';
|
||||
private guessAnimation?: NavDirection;
|
||||
private lastNavId = -1;
|
||||
@@ -65,7 +67,7 @@ export class NavController {
|
||||
* ```
|
||||
*/
|
||||
navigateForward(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
|
||||
this.setDirection('forward', options.animated, options.animationDirection);
|
||||
this.setDirection('forward', options.animated, options.animationDirection, options.animation);
|
||||
return this.navigate(url, options);
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ export class NavController {
|
||||
* ```
|
||||
*/
|
||||
navigateBack(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
|
||||
this.setDirection('back', options.animated, options.animationDirection);
|
||||
this.setDirection('back', options.animated, options.animationDirection, options.animation);
|
||||
return this.navigate(url, options);
|
||||
}
|
||||
|
||||
@@ -111,7 +113,7 @@ export class NavController {
|
||||
* ```
|
||||
*/
|
||||
navigateRoot(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
|
||||
this.setDirection('root', options.animated, options.animationDirection);
|
||||
this.setDirection('root', options.animated, options.animationDirection, options.animation);
|
||||
return this.navigate(url, options);
|
||||
}
|
||||
|
||||
@@ -121,7 +123,7 @@ export class NavController {
|
||||
* by default.
|
||||
*/
|
||||
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
|
||||
this.setDirection('back', options.animated, options.animationDirection);
|
||||
this.setDirection('back', options.animated, options.animationDirection, options.animation);
|
||||
return this.location.back();
|
||||
}
|
||||
|
||||
@@ -150,9 +152,10 @@ export class NavController {
|
||||
*
|
||||
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
|
||||
*/
|
||||
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
|
||||
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) {
|
||||
this.direction = direction;
|
||||
this.animated = getAnimation(direction, animated, animationDirection);
|
||||
this.animationBuilder = animationBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,6 +171,7 @@ export class NavController {
|
||||
consumeTransition() {
|
||||
let direction: RouterDirection = 'root';
|
||||
let animation: NavDirection | undefined;
|
||||
const animationBuilder = this.animationBuilder;
|
||||
|
||||
if (this.direction === 'auto') {
|
||||
direction = this.guessDirection;
|
||||
@@ -178,10 +182,12 @@ export class NavController {
|
||||
}
|
||||
this.direction = DEFAULT_DIRECTION;
|
||||
this.animated = DEFAULT_ANIMATED;
|
||||
this.animationBuilder = undefined;
|
||||
|
||||
return {
|
||||
direction,
|
||||
animation
|
||||
animation,
|
||||
animationBuilder
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { handleErrorMessages, setProperty, getText, waitTime } from './utils';
|
||||
import { handleErrorMessages, getProperty, setProperty, getText, waitTime } from './utils';
|
||||
|
||||
describe('form', () => {
|
||||
|
||||
@@ -7,6 +7,20 @@ describe('form', () => {
|
||||
return handleErrorMessages();
|
||||
});
|
||||
|
||||
describe('status updates', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/form');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should update Ionic form classes when calling form methods programatically', async () => {
|
||||
await element(by.css('form #input-touched')).click();
|
||||
await waitTime(100);
|
||||
const classList = (await getProperty('#touched-input-test', 'classList')) as string[];
|
||||
expect(classList.includes('ion-touched')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('change', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/form');
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons>
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>
|
||||
Alert test
|
||||
</ion-title>
|
||||
|
||||
@@ -35,9 +35,11 @@
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Input (required)</ion-label>
|
||||
<ion-input formControlName="input" class="required"></ion-input>
|
||||
<ion-input formControlName="input" class="required" id="touched-input-test"></ion-input>
|
||||
</ion-item>
|
||||
|
||||
<ion-button id="input-touched" (click)="setTouched()">Set Input Touched</ion-button>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Input</ion-label>
|
||||
<ion-input formControlName="input2"></ion-input>
|
||||
|
||||
@@ -25,6 +25,11 @@ export class FormComponent {
|
||||
});
|
||||
}
|
||||
|
||||
setTouched() {
|
||||
const formControl = this.profileForm.get('input');
|
||||
formControl.markAsTouched();
|
||||
}
|
||||
|
||||
onSubmit(_ev) {
|
||||
this.submitted = 'true';
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item routerLink="/alerts">
|
||||
<ion-item routerLink="/alerts" [routerAnimation]="routerAnimation">
|
||||
<ion-label>
|
||||
Alerts test
|
||||
</ion-label>
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AnimationBuilder, AnimationController } from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home-page',
|
||||
templateUrl: './home-page.component.html',
|
||||
})
|
||||
export class HomePageComponent {
|
||||
routerAnimation: AnimationBuilder = (_, opts) => {
|
||||
const { direction, enteringEl, leavingEl } = opts;
|
||||
const animation = this.animationCtrl.create().duration(500).easing('ease-out');
|
||||
const enteringAnimation = this.animationCtrl.create().addElement(enteringEl).beforeRemoveClass(['ion-page-invisible']);
|
||||
const leavingAnimation = this.animationCtrl.create().addElement(leavingEl).beforeRemoveClass(['ion-page-invisible']);
|
||||
if (direction === 'back') {
|
||||
enteringAnimation.fromTo('transform', 'translateX(-100%)', 'translateX(0%)');
|
||||
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(100%)');
|
||||
} else {
|
||||
enteringAnimation.fromTo('transform', 'translateX(100%)', 'translateX(0%)');
|
||||
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(-100%)');
|
||||
}
|
||||
return animation.addAnimation([enteringAnimation, leavingAnimation]);
|
||||
};
|
||||
|
||||
constructor(private animationCtrl: AnimationController) {}
|
||||
}
|
||||
|
||||
30
core/api.txt
30
core/api.txt
@@ -85,6 +85,7 @@ ion-back-button,prop,defaultHref,string | undefined,undefined,false,false
|
||||
ion-back-button,prop,disabled,boolean,false,false,true
|
||||
ion-back-button,prop,icon,null | string | undefined,undefined,false,false
|
||||
ion-back-button,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-back-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-back-button,prop,text,null | string | undefined,undefined,false,false
|
||||
ion-back-button,prop,type,"button" | "reset" | "submit",'button',false,false
|
||||
ion-back-button,css-prop,--background
|
||||
@@ -119,6 +120,9 @@ ion-back-button,css-prop,--padding-start
|
||||
ion-back-button,css-prop,--padding-top
|
||||
ion-back-button,css-prop,--ripple-color
|
||||
ion-back-button,css-prop,--transition
|
||||
ion-back-button,part,icon
|
||||
ion-back-button,part,native
|
||||
ion-back-button,part,text
|
||||
|
||||
ion-backdrop,shadow
|
||||
ion-backdrop,prop,stopPropagation,boolean,true,false,false
|
||||
@@ -146,6 +150,7 @@ ion-button,prop,fill,"clear" | "default" | "outline" | "solid" | undefined,undef
|
||||
ion-button,prop,href,string | undefined,undefined,false,false
|
||||
ion-button,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-button,prop,rel,string | undefined,undefined,false,false
|
||||
ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
ion-button,prop,shape,"round" | undefined,undefined,false,true
|
||||
ion-button,prop,size,"default" | "large" | "small" | undefined,undefined,false,true
|
||||
@@ -177,6 +182,7 @@ ion-button,css-prop,--padding-start
|
||||
ion-button,css-prop,--padding-top
|
||||
ion-button,css-prop,--ripple-color
|
||||
ion-button,css-prop,--transition
|
||||
ion-button,part,native
|
||||
|
||||
ion-buttons,scoped
|
||||
ion-buttons,prop,collapse,boolean,false,false,false
|
||||
@@ -189,11 +195,13 @@ ion-card,prop,download,string | undefined,undefined,false,false
|
||||
ion-card,prop,href,string | undefined,undefined,false,false
|
||||
ion-card,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-card,prop,rel,string | undefined,undefined,false,false
|
||||
ion-card,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-card,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
ion-card,prop,target,string | undefined,undefined,false,false
|
||||
ion-card,prop,type,"button" | "reset" | "submit",'button',false,false
|
||||
ion-card,css-prop,--background
|
||||
ion-card,css-prop,--color
|
||||
ion-card,part,native
|
||||
|
||||
ion-card-content,none
|
||||
ion-card-content,prop,mode,"ios" | "md",undefined,false,false
|
||||
@@ -288,7 +296,7 @@ ion-content,prop,scrollY,boolean,true,false,false
|
||||
ion-content,method,getScrollElement,getScrollElement() => Promise<HTMLElement>
|
||||
ion-content,method,scrollByPoint,scrollByPoint(x: number, y: number, duration: number) => Promise<void>
|
||||
ion-content,method,scrollToBottom,scrollToBottom(duration?: number) => Promise<void>
|
||||
ion-content,method,scrollToPoint,scrollToPoint(x: number | null | undefined, y: number | null | undefined, duration?: number) => Promise<void>
|
||||
ion-content,method,scrollToPoint,scrollToPoint(x: number | undefined | null, y: number | undefined | null, duration?: number) => Promise<void>
|
||||
ion-content,method,scrollToTop,scrollToTop(duration?: number) => Promise<void>
|
||||
ion-content,event,ionScroll,ScrollDetail,true
|
||||
ion-content,event,ionScrollEnd,ScrollBaseDetail,true
|
||||
@@ -351,12 +359,14 @@ ion-fab,method,close,close() => Promise<void>
|
||||
|
||||
ion-fab-button,shadow
|
||||
ion-fab-button,prop,activated,boolean,false,false,false
|
||||
ion-fab-button,prop,closeIcon,string,'close',false,false
|
||||
ion-fab-button,prop,color,string | undefined,undefined,false,false
|
||||
ion-fab-button,prop,disabled,boolean,false,false,false
|
||||
ion-fab-button,prop,download,string | undefined,undefined,false,false
|
||||
ion-fab-button,prop,href,string | undefined,undefined,false,false
|
||||
ion-fab-button,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-fab-button,prop,rel,string | undefined,undefined,false,false
|
||||
ion-fab-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-fab-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
ion-fab-button,prop,show,boolean,false,false,false
|
||||
ion-fab-button,prop,size,"small" | undefined,undefined,false,false
|
||||
@@ -377,6 +387,7 @@ ion-fab-button,css-prop,--border-radius
|
||||
ion-fab-button,css-prop,--border-style
|
||||
ion-fab-button,css-prop,--border-width
|
||||
ion-fab-button,css-prop,--box-shadow
|
||||
ion-fab-button,css-prop,--close-icon-font-size
|
||||
ion-fab-button,css-prop,--color
|
||||
ion-fab-button,css-prop,--color-activated
|
||||
ion-fab-button,css-prop,--color-focused
|
||||
@@ -387,6 +398,8 @@ ion-fab-button,css-prop,--padding-start
|
||||
ion-fab-button,css-prop,--padding-top
|
||||
ion-fab-button,css-prop,--ripple-color
|
||||
ion-fab-button,css-prop,--transition
|
||||
ion-fab-button,part,close-icon
|
||||
ion-fab-button,part,native
|
||||
|
||||
ion-fab-list,shadow
|
||||
ion-fab-list,prop,activated,boolean,false,false,false
|
||||
@@ -492,6 +505,7 @@ ion-item,prop,href,string | undefined,undefined,false,false
|
||||
ion-item,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
|
||||
ion-item,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-item,prop,rel,string | undefined,undefined,false,false
|
||||
ion-item,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-item,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
ion-item,prop,target,string | undefined,undefined,false,false
|
||||
ion-item,prop,type,"button" | "reset" | "submit",'button',false,false
|
||||
@@ -531,6 +545,7 @@ ion-item,css-prop,--padding-top
|
||||
ion-item,css-prop,--ripple-color
|
||||
ion-item,css-prop,--transition
|
||||
ion-item,part,detail-icon
|
||||
ion-item,part,native
|
||||
|
||||
ion-item-divider,shadow
|
||||
ion-item-divider,prop,color,string | undefined,undefined,false,false
|
||||
@@ -561,6 +576,7 @@ ion-item-option,prop,target,string | undefined,undefined,false,false
|
||||
ion-item-option,prop,type,"button" | "reset" | "submit",'button',false,false
|
||||
ion-item-option,css-prop,--background
|
||||
ion-item-option,css-prop,--color
|
||||
ion-item-option,part,native
|
||||
|
||||
ion-item-options,none
|
||||
ion-item-options,prop,side,"end" | "start",'end',false,false
|
||||
@@ -572,7 +588,7 @@ ion-item-sliding,method,close,close() => Promise<void>
|
||||
ion-item-sliding,method,closeOpened,closeOpened() => Promise<boolean>
|
||||
ion-item-sliding,method,getOpenAmount,getOpenAmount() => Promise<number>
|
||||
ion-item-sliding,method,getSlidingRatio,getSlidingRatio() => Promise<number>
|
||||
ion-item-sliding,method,open,open(side: "start" | "end" | undefined) => Promise<void>
|
||||
ion-item-sliding,method,open,open(side: Side | undefined) => Promise<void>
|
||||
ion-item-sliding,event,ionDrag,any,true
|
||||
|
||||
ion-label,scoped
|
||||
@@ -662,6 +678,7 @@ ion-menu-button,prop,autoHide,boolean,true,false,false
|
||||
ion-menu-button,prop,color,string | undefined,undefined,false,false
|
||||
ion-menu-button,prop,disabled,boolean,false,false,false
|
||||
ion-menu-button,prop,menu,string | undefined,undefined,false,false
|
||||
ion-menu-button,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-menu-button,prop,type,"button" | "reset" | "submit",'button',false,false
|
||||
ion-menu-button,css-prop,--background
|
||||
ion-menu-button,css-prop,--background-focused
|
||||
@@ -676,6 +693,8 @@ ion-menu-button,css-prop,--padding-bottom
|
||||
ion-menu-button,css-prop,--padding-end
|
||||
ion-menu-button,css-prop,--padding-start
|
||||
ion-menu-button,css-prop,--padding-top
|
||||
ion-menu-button,part,icon
|
||||
ion-menu-button,part,native
|
||||
|
||||
ion-menu-toggle,shadow
|
||||
ion-menu-toggle,prop,autoHide,boolean,true,false,false
|
||||
@@ -740,6 +759,7 @@ ion-nav,event,ionNavWillChange,void,false
|
||||
ion-nav-link,none
|
||||
ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false
|
||||
ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
|
||||
ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
|
||||
ion-note,shadow
|
||||
@@ -927,7 +947,7 @@ ion-router,none
|
||||
ion-router,prop,root,string,'/',false,false
|
||||
ion-router,prop,useHash,boolean,true,false,false
|
||||
ion-router,method,back,back() => Promise<void>
|
||||
ion-router,method,push,push(url: string, direction?: RouterDirection) => Promise<boolean>
|
||||
ion-router,method,push,push(url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise<boolean>
|
||||
ion-router,event,ionRouteDidChange,RouterEventDetail,true
|
||||
ion-router,event,ionRouteWillChange,RouterEventDetail,true
|
||||
|
||||
@@ -935,6 +955,7 @@ ion-router-link,shadow
|
||||
ion-router-link,prop,color,string | undefined,undefined,false,false
|
||||
ion-router-link,prop,href,string | undefined,undefined,false,false
|
||||
ion-router-link,prop,rel,string | undefined,undefined,false,false
|
||||
ion-router-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-router-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
|
||||
ion-router-link,prop,target,string | undefined,undefined,false,false
|
||||
ion-router-link,css-prop,--background
|
||||
@@ -1029,6 +1050,8 @@ ion-segment-button,css-prop,--padding-end
|
||||
ion-segment-button,css-prop,--padding-start
|
||||
ion-segment-button,css-prop,--padding-top
|
||||
ion-segment-button,css-prop,--transition
|
||||
ion-segment-button,part,indicator
|
||||
ion-segment-button,part,native
|
||||
|
||||
ion-select,shadow
|
||||
ion-select,prop,cancelText,string,'Cancel',false,false
|
||||
@@ -1166,6 +1189,7 @@ ion-tab-button,css-prop,--padding-end
|
||||
ion-tab-button,css-prop,--padding-start
|
||||
ion-tab-button,css-prop,--padding-top
|
||||
ion-tab-button,css-prop,--ripple-color
|
||||
ion-tab-button,part,native
|
||||
|
||||
ion-tabs,shadow
|
||||
ion-tabs,method,getSelected,getSelected() => Promise<string | undefined>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -34,7 +34,7 @@
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stencil/core": "1.13.0",
|
||||
"@stencil/core": "1.14.0",
|
||||
"@stencil/sass": "1.3.1",
|
||||
"@types/jest": "24.9.1",
|
||||
"@types/node": "12.12.3",
|
||||
|
||||
352
core/src/components.d.ts
vendored
352
core/src/components.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -250,7 +250,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
||||
onIonBackdropTap={this.onBackdropTap}
|
||||
>
|
||||
<ion-backdrop tappable={this.backdropDismiss}/>
|
||||
<div class="action-sheet-wrapper ion-wrapper" role="dialog" ref={el => this.wrapperEl = el}>
|
||||
<div class="action-sheet-wrapper" role="dialog" ref={el => this.wrapperEl = el}>
|
||||
<div class="action-sheet-container">
|
||||
<div class="action-sheet-group" ref={el => this.groupEl = el}>
|
||||
{this.header !== undefined &&
|
||||
|
||||
@@ -514,7 +514,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
|
||||
<ion-backdrop tappable={this.backdropDismiss}/>
|
||||
|
||||
<div class="alert-wrapper ion-wrapper" ref={el => this.wrapperEl = el}>
|
||||
<div class="alert-wrapper" ref={el => this.wrapperEl = el}>
|
||||
|
||||
<div class="alert-head">
|
||||
{header && <h2 id={hdrId} class="alert-title">{header}</h2>}
|
||||
|
||||
@@ -2,12 +2,16 @@ import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/
|
||||
|
||||
import { config } from '../../global/config';
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color } from '../../interface';
|
||||
import { AnimationBuilder, Color } from '../../interface';
|
||||
import { ButtonInterface } from '../../utils/element-interface';
|
||||
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML button element that wraps all child elements.
|
||||
* @part icon - The back button icon (uses ion-icon).
|
||||
* @part text - The back button text.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-back-button',
|
||||
@@ -53,6 +57,12 @@ export class BackButton implements ComponentInterface, ButtonInterface {
|
||||
*/
|
||||
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
componentWillLoad() {
|
||||
if (this.defaultHref === undefined) {
|
||||
this.defaultHref = config.get('backButtonDefaultHref');
|
||||
@@ -99,9 +109,9 @@ export class BackButton implements ComponentInterface, ButtonInterface {
|
||||
ev.preventDefault();
|
||||
|
||||
if (nav && await nav.canGoBack()) {
|
||||
return nav.pop({ skipIfBusy: true });
|
||||
return nav.pop({ animationBuilder: this.routerAnimation, skipIfBusy: true });
|
||||
}
|
||||
return openURL(this.defaultHref, ev, 'back');
|
||||
return openURL(this.defaultHref, ev, 'back', this.routerAnimation);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -126,10 +136,16 @@ export class BackButton implements ComponentInterface, ButtonInterface {
|
||||
'show-back-button': showBackButton
|
||||
}}
|
||||
>
|
||||
<button type={type} disabled={disabled} class="button-native" aria-label={backButtonText || 'back'}>
|
||||
<button
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
class="button-native"
|
||||
part="native"
|
||||
aria-label={backButtonText || 'back'}
|
||||
>
|
||||
<span class="button-inner">
|
||||
{backButtonIcon && <ion-icon icon={backButtonIcon} aria-hidden="true" lazy={false}></ion-icon>}
|
||||
{backButtonText && <span aria-hidden="true" class="button-text">{backButtonText}</span>}
|
||||
{backButtonIcon && <ion-icon part="icon" icon={backButtonIcon} aria-hidden="true" lazy={false}></ion-icon>}
|
||||
{backButtonText && <span part="text" aria-hidden="true" class="button-text">{backButtonText}</span>}
|
||||
</span>
|
||||
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
|
||||
</button>
|
||||
|
||||
@@ -301,15 +301,25 @@ export class BackButtonExample {
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` |
|
||||
| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` |
|
||||
| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ------------------------------------------------------------- |
|
||||
| `"icon"` | The back button icon (uses ion-icon). |
|
||||
| `"native"` | The native HTML button element that wraps all child elements. |
|
||||
| `"text"` | The back button text. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, RouterDirection } from '../../interface';
|
||||
import { AnimationBuilder, Color, RouterDirection } from '../../interface';
|
||||
import { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
|
||||
import { hasShadowDom } from '../../utils/helpers';
|
||||
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
@@ -13,6 +13,8 @@ import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
* @slot icon-only - Should be used on an icon in a button that has no text.
|
||||
* @slot start - Content is placed to the left of the button text in LTR, and to the right in RTL.
|
||||
* @slot end - Content is placed to the right of the button text in LTR, and to the left in RTL.
|
||||
*
|
||||
* @part native - The native HTML button or anchor element that wraps all child elements.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-button',
|
||||
@@ -65,6 +67,12 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
*/
|
||||
@Prop() routerDirection: RouterDirection = 'forward';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page using `href`.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
/**
|
||||
* This attribute instructs browsers to download a URL instead of navigating to
|
||||
* it, so the user will be prompted to save it as a local file. If the attribute
|
||||
@@ -146,7 +154,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
|
||||
private handleClick = (ev: Event) => {
|
||||
if (this.type === 'button') {
|
||||
openURL(this.href, ev, this.routerDirection);
|
||||
openURL(this.href, ev, this.routerDirection, this.routerAnimation);
|
||||
|
||||
} else if (hasShadowDom(this.el)) {
|
||||
// this button wants to specifically submit a form
|
||||
@@ -216,6 +224,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
<TagType
|
||||
{...attrs}
|
||||
class="button-native"
|
||||
part="native"
|
||||
disabled={disabled}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
|
||||
@@ -291,6 +291,7 @@ export class ButtonExample {
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `shape` | `shape` | The button shape. | `"round" \| undefined` | `undefined` |
|
||||
| `size` | `size` | The button size. | `"default" \| "large" \| "small" \| undefined` | `undefined` |
|
||||
@@ -317,6 +318,13 @@ export class ButtonExample {
|
||||
| `"start"` | Content is placed to the left of the button text in LTR, and to the right in RTL. |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ----------------------------------------------------------------------- |
|
||||
| `"native"` | The native HTML button or anchor element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, Mode, RouterDirection } from '../../interface';
|
||||
import { AnimationBuilder, Color, Mode, RouterDirection } from '../../interface';
|
||||
import { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
|
||||
import { createColorClasses, openURL } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML button, anchor, or div element that wraps all child elements.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-card',
|
||||
@@ -66,6 +68,12 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
*/
|
||||
@Prop() routerDirection: RouterDirection = 'forward';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page using `href`.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
/**
|
||||
* Specifies where to display the linked URL.
|
||||
* Only applies when an `href` is provided.
|
||||
@@ -85,7 +93,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
<slot></slot>
|
||||
];
|
||||
}
|
||||
const { href, routerDirection } = this;
|
||||
const { href, routerAnimation, routerDirection } = this;
|
||||
const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div' as any;
|
||||
const attrs = (TagType === 'button')
|
||||
? { type: this.type }
|
||||
@@ -100,8 +108,9 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
<TagType
|
||||
{...attrs}
|
||||
class="card-native"
|
||||
part="native"
|
||||
disabled={this.disabled}
|
||||
onClick={(ev: Event) => openURL(href, ev, routerDirection)}
|
||||
onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)}
|
||||
>
|
||||
<slot></slot>
|
||||
{clickable && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
|
||||
|
||||
@@ -254,18 +254,26 @@ export class CardExample {
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- |
|
||||
| `button` | `button` | If `true`, a button tag will be rendered and the card will be tappable. | `boolean` | `false` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the card. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
|
||||
| `button` | `button` | If `true`, a button tag will be rendered and the card will be tappable. | `boolean` | `false` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the card. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ----------------------------------------------------------------------------- |
|
||||
| `"native"` | The native HTML button, anchor, or div element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
@@ -196,7 +196,7 @@ Type: `Promise<void>`
|
||||
|
||||
|
||||
|
||||
### `scrollToPoint(x: number | null | undefined, y: number | null | undefined, duration?: number) => Promise<void>`
|
||||
### `scrollToPoint(x: number | undefined | null, y: number | undefined | null, duration?: number) => Promise<void>`
|
||||
|
||||
Scroll to a specified X/Y location in the component.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
--color: #{$fab-ios-text-color};
|
||||
--box-shadow: #{$fab-ios-box-shadow};
|
||||
--transition: #{$fab-ios-transition};
|
||||
--close-icon-font-size: #{$fab-ios-icon-font-size};
|
||||
}
|
||||
|
||||
:host(.ion-activated) {
|
||||
@@ -23,11 +24,11 @@
|
||||
--transition: #{$fab-ios-transition-activated};
|
||||
}
|
||||
|
||||
::slotted(ion-icon),
|
||||
.close-icon {
|
||||
::slotted(ion-icon) {
|
||||
font-size: $fab-ios-icon-font-size;
|
||||
}
|
||||
|
||||
|
||||
// FAB buttons in a list
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -112,4 +113,4 @@
|
||||
:host(.ion-color.ion-activated.fab-button-translucent) .button-native {
|
||||
background: #{current-color(base)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
opacity 15ms linear 30ms,
|
||||
transform 270ms cubic-bezier(0, 0, .2, 1) 0ms
|
||||
};
|
||||
--close-icon-font-size: #{$fab-md-icon-font-size};
|
||||
}
|
||||
|
||||
:host(.ion-activated) {
|
||||
--box-shadow: #{$fab-md-box-shadow-activated};
|
||||
}
|
||||
|
||||
::slotted(ion-icon),
|
||||
.close-icon {
|
||||
::slotted(ion-icon) {
|
||||
font-size: $fab-md-icon-font-size;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*
|
||||
* @prop --transition: Transition of the button
|
||||
*
|
||||
* @prop --close-icon-font-size: Font size of the close icon
|
||||
*
|
||||
* @prop --border-radius: Border radius of the button
|
||||
* @prop --border-width: Border width of the button
|
||||
* @prop --border-style: Border style of the button
|
||||
@@ -207,14 +209,11 @@
|
||||
// --------------------------------------------------
|
||||
|
||||
.close-icon {
|
||||
@include margin(0, auto);
|
||||
@include position(0, 0, null, 0);
|
||||
|
||||
display: flex;
|
||||
position: absolute;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
|
||||
transform: scale(.4) rotateZ(-45deg);
|
||||
@@ -222,11 +221,14 @@
|
||||
transition: all ease-in-out 300ms;
|
||||
transition-property: transform, opacity;
|
||||
|
||||
font-size: var(--close-icon-font-size);
|
||||
|
||||
opacity: 0;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
// FAB Animation
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, RouterDirection } from '../../interface';
|
||||
import { AnimationBuilder, Color, RouterDirection } from '../../interface';
|
||||
import { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
|
||||
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML button or anchor element that wraps all child elements.
|
||||
* @part close-icon - The close icon that is displayed when a fab list opens (uses ion-icon).
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-fab-button',
|
||||
@@ -62,6 +65,12 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
|
||||
*/
|
||||
@Prop() routerDirection: RouterDirection = 'forward';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page using `href`.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
/**
|
||||
* Specifies where to display the linked URL.
|
||||
* Only applies when an `href` is provided.
|
||||
@@ -87,10 +96,17 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
|
||||
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
||||
|
||||
/**
|
||||
* The size of the button. Set this to `small` in order to have a mini fab.
|
||||
* The size of the button. Set this to `small` in order to have a mini fab button.
|
||||
*/
|
||||
@Prop() size?: 'small';
|
||||
|
||||
/**
|
||||
* The icon name to use for the close icon. This will appear when the fab button
|
||||
* is pressed. Only applies if it is the main button inside of a fab containing a
|
||||
* fab list.
|
||||
*/
|
||||
@Prop() closeIcon = 'close';
|
||||
|
||||
/**
|
||||
* Emitted when the button has focus.
|
||||
*/
|
||||
@@ -144,14 +160,13 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
|
||||
<TagType
|
||||
{...attrs}
|
||||
class="button-native"
|
||||
part="native"
|
||||
disabled={disabled}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
onClick={(ev: Event) => openURL(href, ev, this.routerDirection)}
|
||||
onClick={(ev: Event) => openURL(href, ev, this.routerDirection, this.routerAnimation)}
|
||||
>
|
||||
<span class="close-icon">
|
||||
<ion-icon name="close" lazy={false}></ion-icon>
|
||||
</span>
|
||||
<ion-icon icon={this.closeIcon} part="close-icon" class="close-icon" lazy={false}></ion-icon>
|
||||
<span class="button-inner">
|
||||
<slot></slot>
|
||||
</span>
|
||||
|
||||
@@ -137,21 +137,23 @@ export class FabButtonExample {
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- |
|
||||
| `activated` | `activated` | If `true`, the fab button will be show a close icon. | `boolean` | `false` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the fab button. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `show` | `show` | If `true`, the fab button will show when in a fab-list. | `boolean` | `false` |
|
||||
| `size` | `size` | The size of the button. Set this to `small` in order to have a mini fab. | `"small" \| undefined` | `undefined` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `translucent` | `translucent` | If `true`, the fab button will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). | `boolean` | `false` |
|
||||
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
|
||||
| `activated` | `activated` | If `true`, the fab button will be show a close icon. | `boolean` | `false` |
|
||||
| `closeIcon` | `close-icon` | The icon name to use for the close icon. This will appear when the fab button is pressed. Only applies if it is the main button inside of a fab containing a fab list. | `string` | `'close'` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the fab button. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `show` | `show` | If `true`, the fab button will show when in a fab-list. | `boolean` | `false` |
|
||||
| `size` | `size` | The size of the button. Set this to `small` in order to have a mini fab button. | `"small" \| undefined` | `undefined` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `translucent` | `translucent` | If `true`, the fab button will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). | `boolean` | `false` |
|
||||
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
|
||||
|
||||
## Events
|
||||
@@ -162,6 +164,14 @@ export class FabButtonExample {
|
||||
| `ionFocus` | Emitted when the button has focus. | `CustomEvent<void>` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| -------------- | ----------------------------------------------------------------------- |
|
||||
| `"close-icon"` | The close icon that is displayed when a fab list opens (uses ion-icon). |
|
||||
| `"native"` | The native HTML button or anchor element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
@@ -178,6 +188,7 @@ export class FabButtonExample {
|
||||
| `--border-style` | Border style of the button |
|
||||
| `--border-width` | Border width of the button |
|
||||
| `--box-shadow` | Box shadow of the button |
|
||||
| `--close-icon-font-size` | Font size of the close icon |
|
||||
| `--color` | Text color of the button |
|
||||
| `--color-activated` | Text color of the button when pressed |
|
||||
| `--color-focused` | Text color of the button when focused with the tab key |
|
||||
|
||||
@@ -71,6 +71,22 @@
|
||||
<ion-fab-button class="fab-button-in-list custom-border"><ion-icon name="star"></ion-icon></ion-fab-button>
|
||||
<ion-fab-button class="fab-button-in-list custom-border ion-activated"><ion-icon name="star"></ion-icon></ion-fab-button>
|
||||
|
||||
<ion-fab slot="fixed" horizontal="center" vertical="bottom">
|
||||
<ion-fab-button class="custom-close"><ion-icon name="star"></ion-icon></ion-fab-button>
|
||||
|
||||
<ion-fab-list side="top">
|
||||
<ion-fab-button>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="square"></ion-icon>
|
||||
</ion-fab-button>
|
||||
<ion-fab-button>
|
||||
<ion-icon name="triangle"></ion-icon>
|
||||
</ion-fab-button>
|
||||
</ion-fab-list>
|
||||
</ion-fab>
|
||||
|
||||
<style>
|
||||
ion-fab-button {
|
||||
display: inline-block;
|
||||
@@ -104,6 +120,12 @@
|
||||
--border-style: dashed;
|
||||
--border-color: red;
|
||||
}
|
||||
|
||||
.custom-close::part(close-icon) {
|
||||
color: red;
|
||||
|
||||
font-size: 44px;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -200,7 +200,6 @@
|
||||
f:last-of-type {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
</style>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
@@ -53,7 +53,11 @@ export class Img implements ComponentInterface {
|
||||
if (this.src === undefined) {
|
||||
return;
|
||||
}
|
||||
if ('IntersectionObserver' in window) {
|
||||
if (
|
||||
typeof (window as any) !== 'undefined' &&
|
||||
'IntersectionObserver' in window &&
|
||||
'IntersectionObserverEntry' in window &&
|
||||
'isIntersecting' in window.IntersectionObserverEntry.prototype) {
|
||||
this.removeIO();
|
||||
this.io = new IntersectionObserver(data => {
|
||||
// because there will only ever be one instance
|
||||
|
||||
@@ -393,7 +393,7 @@ export class Input implements ComponentInterface {
|
||||
placeholder={this.placeholder || ''}
|
||||
readOnly={this.readonly}
|
||||
required={this.required}
|
||||
spellcheck={this.spellcheck ? 'true' : undefined}
|
||||
spellcheck={this.spellcheck}
|
||||
step={this.step}
|
||||
size={this.size}
|
||||
tabindex={this.tabindex}
|
||||
@@ -405,6 +405,7 @@ export class Input implements ComponentInterface {
|
||||
onKeyDown={this.onKeydown}
|
||||
/>
|
||||
{(this.clearInput && !this.readonly && !this.disabled) && <button
|
||||
aria-label="reset"
|
||||
type="button"
|
||||
class="input-clear-icon"
|
||||
tabindex="-1"
|
||||
|
||||
@@ -14,6 +14,8 @@ import { createColorClasses } from '../../utils/theme';
|
||||
* @slot icon-only - Should be used on an icon in an option that has no text.
|
||||
* @slot bottom - Content is placed below the option text.
|
||||
* @slot end - Content is placed to the right of the option text in LTR, and to the left in RTL.
|
||||
*
|
||||
* @part native - The native HTML button or anchor element that wraps all child elements.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-item-option',
|
||||
@@ -110,6 +112,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
|
||||
<TagType
|
||||
{...attrs}
|
||||
class="button-native"
|
||||
part="native"
|
||||
disabled={disabled}
|
||||
>
|
||||
<span class="button-inner">
|
||||
|
||||
@@ -34,6 +34,13 @@ action for the item.
|
||||
| `"top"` | Content is placed above the option text. |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ----------------------------------------------------------------------- |
|
||||
| `"native"` | The native HTML button or anchor element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
|
||||
@@ -860,7 +860,7 @@ Type: `Promise<number>`
|
||||
|
||||
|
||||
|
||||
### `open(side: "start" | "end" | undefined) => Promise<void>`
|
||||
### `open(side: Side | undefined) => Promise<void>`
|
||||
|
||||
Open the sliding item.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ComponentInterface, Element, Host, Listen, Prop, State, forceUpdate, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, CssClassMap, RouterDirection, StyleEventDetail } from '../../interface';
|
||||
import { AnimationBuilder, Color, CssClassMap, RouterDirection, StyleEventDetail } from '../../interface';
|
||||
import { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
|
||||
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
|
||||
@@ -12,6 +12,7 @@ import { createColorClasses, hostContext, openURL } from '../../utils/theme';
|
||||
* @slot start - Content is placed to the left of the item text in LTR, and to the right in RTL.
|
||||
* @slot end - Content is placed to the right of the item text in LTR, and to the left in RTL.
|
||||
*
|
||||
* @part native - The native HTML button, anchor or div element that wraps all child elements.
|
||||
* @part detail-icon - The chevron icon for the item. Only applies when `detail="true"`.
|
||||
*/
|
||||
@Component({
|
||||
@@ -85,6 +86,12 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
*/
|
||||
@Prop() lines?: 'full' | 'inset' | 'none';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page using `href`.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition direction when navigating to
|
||||
* another page using `href`.
|
||||
@@ -170,7 +177,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
}
|
||||
|
||||
render() {
|
||||
const { detail, detailIcon, download, lines, disabled, href, rel, target, routerDirection } = this;
|
||||
const { detail, detailIcon, download, lines, disabled, href, rel, target, routerAnimation, routerDirection } = this;
|
||||
const childStyles = {};
|
||||
const mode = getIonMode(this);
|
||||
const clickable = this.isClickable();
|
||||
@@ -208,8 +215,9 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
<TagType
|
||||
{...attrs}
|
||||
class="item-native"
|
||||
part="native"
|
||||
disabled={disabled}
|
||||
onClick={(ev: Event) => openURL(href, ev, routerDirection)}
|
||||
onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)}
|
||||
>
|
||||
<slot name="start"></slot>
|
||||
<div class="item-inner">
|
||||
|
||||
@@ -1783,21 +1783,22 @@ export class ItemExample {
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------- |
|
||||
| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` |
|
||||
| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'chevron-forward'` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------- |
|
||||
| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` |
|
||||
| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'chevron-forward'` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` |
|
||||
| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
|
||||
|
||||
## Slots
|
||||
@@ -1811,9 +1812,10 @@ export class ItemExample {
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| --------------- | ----------------------------------------------------------------- |
|
||||
| `"detail-icon"` | The chevron icon for the item. Only applies when `detail="true"`. |
|
||||
| Part | Description |
|
||||
| --------------- | ---------------------------------------------------------------------------- |
|
||||
| `"detail-icon"` | The chevron icon for the item. Only applies when `detail="true"`. |
|
||||
| `"native"` | The native HTML button, anchor or div element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
@@ -194,7 +194,7 @@ export class Loading implements ComponentInterface, OverlayInterface {
|
||||
}}
|
||||
>
|
||||
<ion-backdrop visible={this.showBackdrop} tappable={this.backdropDismiss} />
|
||||
<div class="loading-wrapper ion-wrapper" role="dialog">
|
||||
<div class="loading-wrapper" role="dialog">
|
||||
{spinner && (
|
||||
<div class="loading-spinner">
|
||||
<ion-spinner name={spinner} aria-hidden="true" />
|
||||
|
||||
@@ -8,6 +8,12 @@ import { menuController } from '../../utils/menu-controller';
|
||||
import { createColorClasses, hostContext } from '../../utils/theme';
|
||||
import { updateVisibility } from '../menu-toggle/menu-toggle-util';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML button element that wraps all child elements.
|
||||
* @part icon - The menu button icon (uses ion-icon).
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-menu-button',
|
||||
styleUrls: {
|
||||
@@ -95,11 +101,12 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
||||
{...attrs}
|
||||
disabled={disabled}
|
||||
class="button-native"
|
||||
part="native"
|
||||
aria-label="menu"
|
||||
>
|
||||
<span class="button-inner">
|
||||
<slot>
|
||||
<ion-icon icon={menuIcon} mode={mode} lazy={false} aria-hidden="true"></ion-icon>
|
||||
<ion-icon part="icon" icon={menuIcon} mode={mode} lazy={false} aria-hidden="true"></ion-icon>
|
||||
</slot>
|
||||
</span>
|
||||
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
|
||||
|
||||
@@ -14,9 +14,18 @@ Menu Button is component that automatically creates the icon and functionality t
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the menu button. | `boolean` | `false` |
|
||||
| `menu` | `menu` | Optional property that maps to a Menu's `menuId` prop. Can also be `start` or `end` for the menu side. This is used to find the correct menu to toggle | `string \| undefined` | `undefined` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
|
||||
| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ------------------------------------------------------------- |
|
||||
| `"icon"` | The menu button icon (uses ion-icon). |
|
||||
| `"native"` | The native HTML button element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
@supports (width: max(0px, 1px)) {
|
||||
:host(.modal-card) .modal-wrapper {
|
||||
height: calc(100% - max(30px, var(--ion-safe-area-top)) - 10px);
|
||||
:host(.modal-card) {
|
||||
--height: calc(100% - max(30px, var(--ion-safe-area-top)) - 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@supports not (width: max(0px, 1px)) {
|
||||
:host(.modal-card) .modal-wrapper {
|
||||
height: calc(100% - 40px);
|
||||
:host(.modal-card) {
|
||||
--height: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
{mode === 'ios' && <div class="modal-shadow"></div>}
|
||||
<div
|
||||
role="dialog"
|
||||
class="modal-wrapper ion-wrapper"
|
||||
class="modal-wrapper"
|
||||
>
|
||||
</div>
|
||||
</Host>
|
||||
|
||||
@@ -173,6 +173,8 @@ export class CalendarComponentModule {}
|
||||
|
||||
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.
|
||||
|
||||
If you are creating an application that uses `ion-tabs`, it is recommended that you get the parent `ion-router-outlet` using `this.routerOutlet.parentOutlet.nativeEl`, otherwise the tabbar will not scale down when the modal opens.
|
||||
|
||||
```javascript
|
||||
@@ -302,6 +304,8 @@ console.log(data);
|
||||
|
||||
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.
|
||||
|
||||
```javascript
|
||||
const modalElement = document.createElement('ion-modal');
|
||||
modalElement.component = 'modal-page';
|
||||
@@ -346,6 +350,8 @@ export const ModalExample: React.FC = () => {
|
||||
|
||||
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.
|
||||
|
||||
```tsx
|
||||
<IonModal
|
||||
isOpen={showModal}
|
||||
@@ -496,6 +502,8 @@ console.log(data);
|
||||
|
||||
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.
|
||||
|
||||
```tsx
|
||||
import { Component, Element, h } from '@stencil/core';
|
||||
|
||||
|
||||
@@ -130,6 +130,8 @@ export class CalendarComponentModule {}
|
||||
|
||||
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.
|
||||
|
||||
If you are creating an application that uses `ion-tabs`, it is recommended that you get the parent `ion-router-outlet` using `this.routerOutlet.parentOutlet.nativeEl`, otherwise the tabbar will not scale down when the modal opens.
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -84,6 +84,8 @@ console.log(data);
|
||||
|
||||
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.
|
||||
|
||||
```javascript
|
||||
const modalElement = document.createElement('ion-modal');
|
||||
modalElement.component = 'modal-page';
|
||||
|
||||
@@ -21,6 +21,8 @@ export const ModalExample: React.FC = () => {
|
||||
|
||||
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.
|
||||
|
||||
```tsx
|
||||
<IonModal
|
||||
isOpen={showModal}
|
||||
|
||||
@@ -109,6 +109,8 @@ console.log(data);
|
||||
|
||||
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.
|
||||
|
||||
```tsx
|
||||
import { Component, Element, h } from '@stencil/core';
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { ComponentProps, NavComponent } from '../../interface';
|
||||
import { AnimationBuilder, ComponentProps, NavComponent } from '../../interface';
|
||||
import { RouterDirection } from '../router/utils/interface';
|
||||
|
||||
export const navLink = (el: HTMLElement, routerDirection: RouterDirection, component?: NavComponent, componentProps?: ComponentProps) => {
|
||||
export const navLink = (el: HTMLElement, routerDirection: RouterDirection, component?: NavComponent, componentProps?: ComponentProps, routerAnimation?: AnimationBuilder) => {
|
||||
const nav = el.closest('ion-nav');
|
||||
if (nav) {
|
||||
if (routerDirection === 'forward') {
|
||||
if (component !== undefined) {
|
||||
return nav.push(component, componentProps, { skipIfBusy: true });
|
||||
return nav.push(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation });
|
||||
}
|
||||
} else if (routerDirection === 'root') {
|
||||
if (component !== undefined) {
|
||||
return nav.setRoot(component, componentProps, { skipIfBusy: true });
|
||||
return nav.setRoot(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation });
|
||||
}
|
||||
} else if (routerDirection === 'back') {
|
||||
return nav.pop({ skipIfBusy: true });
|
||||
return nav.pop({ skipIfBusy: true, animationBuilder: routerAnimation });
|
||||
}
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { ComponentProps, NavComponent, RouterDirection } from '../../interface';
|
||||
import { AnimationBuilder, ComponentProps, NavComponent, RouterDirection } from '../../interface';
|
||||
|
||||
import { navLink } from './nav-link-utils';
|
||||
|
||||
@@ -25,8 +25,13 @@ export class NavLink implements ComponentInterface {
|
||||
*/
|
||||
@Prop() routerDirection: RouterDirection = 'forward';
|
||||
|
||||
/**
|
||||
* The transition animation when navigating to another page.
|
||||
*/
|
||||
@Prop() routerAnimation?: AnimationBuilder;
|
||||
|
||||
private onClick = () => {
|
||||
return navLink(this.el, this.routerDirection, this.component, this.componentProps);
|
||||
return navLink(this.el, this.routerDirection, this.component, this.componentProps, this.routerAnimation);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -14,6 +14,7 @@ It is the element form of calling the `push()`, `pop()`, and `setRoot()` methods
|
||||
| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------- |
|
||||
| `component` | `component` | Component to navigate to. Only used if the `routerDirection` is `"forward"` or `"root"`. | `Function \| HTMLElement \| ViewController \| null \| string \| undefined` | `undefined` |
|
||||
| `componentProps` | -- | Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`. | `undefined \| { [key: string]: any; }` | `undefined` |
|
||||
| `routerAnimation` | -- | The transition animation when navigating to another page. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | The transition direction when navigating to another page. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
|
||||
|
||||
|
||||
@@ -372,7 +372,8 @@ export class Nav implements NavOutlet {
|
||||
setRouteId(
|
||||
id: string,
|
||||
params: ComponentProps | undefined,
|
||||
direction: RouterDirection
|
||||
direction: RouterDirection,
|
||||
animation?: AnimationBuilder
|
||||
): Promise<RouteWrite> {
|
||||
const active = this.getActiveSync();
|
||||
if (matches(active, id, params)) {
|
||||
@@ -410,15 +411,20 @@ export class Nav implements NavOutlet {
|
||||
if (viewController) {
|
||||
finish = this.popTo(viewController, {
|
||||
...commonOpts,
|
||||
direction: 'back'
|
||||
direction: 'back',
|
||||
animationBuilder: animation
|
||||
});
|
||||
} else if (direction === 'forward') {
|
||||
finish = this.push(id, params, commonOpts);
|
||||
finish = this.push(id, params, {
|
||||
...commonOpts,
|
||||
animationBuilder: animation
|
||||
});
|
||||
} else if (direction === 'back') {
|
||||
finish = this.setRoot(id, params, {
|
||||
...commonOpts,
|
||||
direction: 'back',
|
||||
animated: true
|
||||
animated: true,
|
||||
animationBuilder: animation
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -623,6 +629,19 @@ export class Nav implements NavOutlet {
|
||||
const requiresTransition =
|
||||
(ti.enteringRequiresTransition || ti.leavingRequiresTransition) &&
|
||||
enteringView !== leavingView;
|
||||
if (requiresTransition && ti.opts && leavingView) {
|
||||
const isBackDirection = ti.opts.direction === 'back';
|
||||
|
||||
/**
|
||||
* If heading back, use the entering page's animation
|
||||
* unless otherwise specified by the developer.
|
||||
*/
|
||||
if (isBackDirection) {
|
||||
ti.opts.animationBuilder = ti.opts.animationBuilder || (enteringView && enteringView.animationBuilder);
|
||||
}
|
||||
|
||||
leavingView.animationBuilder = ti.opts.animationBuilder;
|
||||
}
|
||||
const result = requiresTransition
|
||||
? await this.transition(enteringView!, leavingView, ti)
|
||||
: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ComponentProps, FrameworkDelegate } from '../../interface';
|
||||
import { AnimationBuilder, ComponentProps, FrameworkDelegate } from '../../interface';
|
||||
import { attachComponent } from '../../utils/framework-delegate';
|
||||
import { assert } from '../../utils/helpers';
|
||||
|
||||
@@ -12,6 +12,7 @@ export class ViewController {
|
||||
nav?: any;
|
||||
element?: HTMLElement;
|
||||
delegate?: FrameworkDelegate;
|
||||
animationBuilder?: AnimationBuilder;
|
||||
|
||||
constructor(
|
||||
public component: any,
|
||||
|
||||
@@ -236,7 +236,7 @@ export class Picker implements ComponentInterface, OverlayInterface {
|
||||
tappable={this.backdropDismiss}
|
||||
>
|
||||
</ion-backdrop>
|
||||
<div class="picker-wrapper ion-wrapper" role="dialog">
|
||||
<div class="picker-wrapper" role="dialog">
|
||||
<div class="picker-toolbar">
|
||||
{this.buttons.map(b => (
|
||||
<div class={buttonWrapperClass(b)}>
|
||||
|
||||
@@ -219,7 +219,7 @@ export class Popover implements ComponentInterface, OverlayInterface {
|
||||
onIonBackdropTap={this.onBackdropTap}
|
||||
>
|
||||
<ion-backdrop tappable={this.backdropDismiss} visible={this.showBackdrop}/>
|
||||
<div class="popover-wrapper ion-wrapper">
|
||||
<div class="popover-wrapper">
|
||||
<div class="popover-arrow"></div>
|
||||
<div class="popover-content"></div>
|
||||
</div>
|
||||
|
||||
@@ -315,9 +315,9 @@ export class ReorderExample {
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| -------- | ------------------------------- |
|
||||
| `"icon"` | The icon of the reorder handle. |
|
||||
| Part | Description |
|
||||
| -------- | ----------------------------------------------- |
|
||||
| `"icon"` | The icon of the reorder handle (uses ion-icon). |
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Component, ComponentInterface, Host, Listen, h } from '@stencil/core';
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
|
||||
/**
|
||||
* @part icon - The icon of the reorder handle.
|
||||
* @part icon - The icon of the reorder handle (uses ion-icon).
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-reorder',
|
||||
|
||||
@@ -9,13 +9,14 @@ The router link component is used for navigating to a specified link. Similar to
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
| Property | Attribute | Description | Type | Default |
|
||||
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- |
|
||||
| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
|
||||
| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` |
|
||||
| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` |
|
||||
| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` |
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import { Color, RouterDirection } from '../../interface';
|
||||
import { AnimationBuilder, Color, RouterDirection } from '../../interface';
|
||||
import { createColorClasses, openURL } from '../../utils/theme';
|
||||
|
||||
@Component({
|
||||
@@ -36,6 +36,12 @@ export class RouterLink implements ComponentInterface {
|
||||
*/
|
||||
@Prop() routerDirection: RouterDirection = 'forward';
|
||||
|
||||
/**
|
||||
* When using a router, it specifies the transition animation when navigating to
|
||||
* another page using `href`.
|
||||
*/
|
||||
@Prop() routerAnimation: AnimationBuilder | undefined;
|
||||
|
||||
/**
|
||||
* Specifies where to display the linked URL.
|
||||
* Only applies when an `href` is provided.
|
||||
@@ -44,7 +50,7 @@ export class RouterLink implements ComponentInterface {
|
||||
@Prop() target: string | undefined;
|
||||
|
||||
private onClick = (ev: Event) => {
|
||||
openURL(this.href, ev, this.routerDirection);
|
||||
openURL(this.href, ev, this.routerDirection, this.routerAnimation);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -131,10 +131,11 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
||||
|
||||
/** @internal */
|
||||
@Method()
|
||||
async setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise<RouteWrite> {
|
||||
async setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder): Promise<RouteWrite> {
|
||||
const changed = await this.setRoot(id, params, {
|
||||
duration: direction === 'root' ? 0 : undefined,
|
||||
direction: direction === 'back' ? 'back' : 'forward',
|
||||
animationBuilder: animation
|
||||
});
|
||||
return {
|
||||
changed,
|
||||
@@ -186,7 +187,6 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
||||
await transition({
|
||||
mode,
|
||||
animated,
|
||||
animationBuilder,
|
||||
enteringEl,
|
||||
leavingEl,
|
||||
baseEl: el,
|
||||
@@ -194,7 +194,8 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
|
||||
? ani => this.ani = ani
|
||||
: undefined
|
||||
),
|
||||
...opts
|
||||
...opts,
|
||||
animationBuilder,
|
||||
});
|
||||
|
||||
// emit nav changed event
|
||||
|
||||
@@ -78,7 +78,7 @@ Type: `Promise<void>`
|
||||
|
||||
|
||||
|
||||
### `push(url: string, direction?: RouterDirection) => Promise<boolean>`
|
||||
### `push(url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise<boolean>`
|
||||
|
||||
Navigate to the specified URL.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { BackButtonEvent, RouteChain, RouterDirection, RouterEventDetail } from '../../interface';
|
||||
import { AnimationBuilder, BackButtonEvent, RouteChain, RouterDirection, RouterEventDetail } from '../../interface';
|
||||
import { debounce } from '../../utils/helpers';
|
||||
|
||||
import { ROUTER_INTENT_BACK, ROUTER_INTENT_FORWARD, ROUTER_INTENT_NONE } from './utils/constants';
|
||||
@@ -92,7 +92,7 @@ export class Router implements ComponentInterface {
|
||||
* @param direction The direction of the animation. Defaults to `"forward"`.
|
||||
*/
|
||||
@Method()
|
||||
push(url: string, direction: RouterDirection = 'forward') {
|
||||
push(url: string, direction: RouterDirection = 'forward', animation?: AnimationBuilder) {
|
||||
if (url.startsWith('.')) {
|
||||
url = (new URL(url, window.location.href)).pathname;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ export class Router implements ComponentInterface {
|
||||
const path = parsePath(url);
|
||||
const queryString = url.split('?')[1];
|
||||
this.setPath(path, direction, queryString);
|
||||
return this.writeNavStateRoot(path, direction);
|
||||
return this.writeNavStateRoot(path, direction, animation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +173,7 @@ export class Router implements ComponentInterface {
|
||||
const lastState = this.lastState;
|
||||
this.lastState = state;
|
||||
|
||||
if (state > lastState) {
|
||||
if (state > lastState || (state >= lastState && lastState > 0)) {
|
||||
return ROUTER_INTENT_FORWARD;
|
||||
} else if (state < lastState) {
|
||||
return ROUTER_INTENT_BACK;
|
||||
@@ -182,7 +182,7 @@ export class Router implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private async writeNavStateRoot(path: string[] | null, direction: RouterDirection): Promise<boolean> {
|
||||
private async writeNavStateRoot(path: string[] | null, direction: RouterDirection, animation?: AnimationBuilder): Promise<boolean> {
|
||||
if (!path) {
|
||||
console.error('[ion-router] URL is not part of the routing set');
|
||||
return false;
|
||||
@@ -207,18 +207,19 @@ export class Router implements ComponentInterface {
|
||||
}
|
||||
|
||||
// write DOM give
|
||||
return this.safeWriteNavState(document.body, chain, direction, path, redirectFrom);
|
||||
return this.safeWriteNavState(document.body, chain, direction, path, redirectFrom, 0, animation);
|
||||
}
|
||||
|
||||
private async safeWriteNavState(
|
||||
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||
path: string[], redirectFrom: string[] | null,
|
||||
index = 0
|
||||
index = 0,
|
||||
animation?: AnimationBuilder
|
||||
): Promise<boolean> {
|
||||
const unlock = await this.lock();
|
||||
let changed = false;
|
||||
try {
|
||||
changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index);
|
||||
changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index, animation);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -240,7 +241,7 @@ export class Router implements ComponentInterface {
|
||||
private async writeNavState(
|
||||
node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection,
|
||||
path: string[], redirectFrom: string[] | null,
|
||||
index = 0
|
||||
index = 0, animation?: AnimationBuilder
|
||||
): Promise<boolean> {
|
||||
if (this.busy) {
|
||||
console.warn('[ion-router] router is busy, transition was cancelled');
|
||||
@@ -254,7 +255,7 @@ export class Router implements ComponentInterface {
|
||||
this.ionRouteWillChange.emit(routeEvent);
|
||||
}
|
||||
|
||||
const changed = await writeNavState(node, chain, direction, index);
|
||||
const changed = await writeNavState(node, chain, direction, index, false, animation);
|
||||
this.busy = false;
|
||||
|
||||
if (changed) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NavOutletElement, RouteChain, RouteID, RouterDirection } from '../../../interface';
|
||||
import { AnimationBuilder, NavOutletElement, RouteChain, RouteID, RouterDirection } from '../../../interface';
|
||||
|
||||
import { ROUTER_INTENT_NONE } from './constants';
|
||||
|
||||
@@ -7,7 +7,8 @@ export const writeNavState = async (
|
||||
chain: RouteChain,
|
||||
direction: RouterDirection,
|
||||
index: number,
|
||||
changed = false
|
||||
changed = false,
|
||||
animation?: AnimationBuilder
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
// find next navigation outlet in the DOM
|
||||
@@ -20,7 +21,7 @@ export const writeNavState = async (
|
||||
await outlet.componentOnReady();
|
||||
|
||||
const route = chain[index];
|
||||
const result = await outlet.setRouteId(route.id, route.params, direction);
|
||||
const result = await outlet.setRouteId(route.id, route.params, direction, animation);
|
||||
|
||||
// if the outlet changed the page, reset navigation to neutral (no direction)
|
||||
// this means nested outlets will not animate
|
||||
@@ -30,7 +31,7 @@ export const writeNavState = async (
|
||||
}
|
||||
|
||||
// recursively set nested outlets
|
||||
changed = await writeNavState(result.element, chain, direction, index + 1, changed);
|
||||
changed = await writeNavState(result.element, chain, direction, index + 1, changed, animation);
|
||||
|
||||
// once all nested outlets are visible let's make the parent visible too,
|
||||
// using markVisible prevents flickering
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ComponentProps } from '../../../interface';
|
||||
import { AnimationBuilder, ComponentProps } from '../../../interface';
|
||||
|
||||
export interface HTMLStencilElement extends HTMLElement {
|
||||
componentOnReady(): Promise<this>;
|
||||
}
|
||||
|
||||
export interface NavOutlet {
|
||||
setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise<RouteWrite>;
|
||||
setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder): Promise<RouteWrite>;
|
||||
getRouteId(): Promise<RouteID | undefined>;
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ export class Searchbar implements ComponentInterface {
|
||||
value={this.getValue()}
|
||||
autoComplete={this.autocomplete}
|
||||
autoCorrect={this.autocorrect}
|
||||
spellcheck={this.spellcheck ? 'true' : undefined}
|
||||
spellcheck={this.spellcheck}
|
||||
/>
|
||||
|
||||
{mode === 'md' && cancelButton}
|
||||
|
||||
@@ -794,6 +794,14 @@ export class SegmentButtonExample {
|
||||
| `value` | `value` | The value of the segment button. | `string` | `'ion-sb-' + (ids++)` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ------------- | ------------------------------------------------------------- |
|
||||
| `"indicator"` | The indicator displayed on the checked segment button. |
|
||||
| `"native"` | The native HTML button element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
|
||||
@@ -9,6 +9,9 @@ let ids = 0;
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML button element that wraps all child elements.
|
||||
* @part indicator - The indicator displayed on the checked segment button.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-segment-button',
|
||||
@@ -103,6 +106,7 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {
|
||||
type={type}
|
||||
aria-pressed={checked ? 'true' : 'false'}
|
||||
class="button-native"
|
||||
part="native"
|
||||
disabled={disabled}
|
||||
>
|
||||
<span class="button-inner">
|
||||
|
||||
@@ -213,6 +213,7 @@ export class Segment implements ComponentInterface {
|
||||
// If there are no checked buttons, set the current button to checked
|
||||
if (!checked) {
|
||||
this.value = clicked.value;
|
||||
this.setCheckedClasses();
|
||||
}
|
||||
|
||||
// If the gesture began on the clicked button with the indicator
|
||||
@@ -375,8 +376,12 @@ export class Segment implements ComponentInterface {
|
||||
const previous = this.checked;
|
||||
this.value = current.value;
|
||||
|
||||
if (previous && this.scrollable) {
|
||||
this.checkButton(previous, current);
|
||||
if (this.scrollable) {
|
||||
if (previous) {
|
||||
this.checkButton(previous, current);
|
||||
} else {
|
||||
this.setCheckedClasses();
|
||||
}
|
||||
}
|
||||
|
||||
this.checked = current;
|
||||
|
||||
@@ -232,6 +232,13 @@ export class TabButtonExample {
|
||||
| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` |
|
||||
|
||||
|
||||
## Shadow Parts
|
||||
|
||||
| Part | Description |
|
||||
| ---------- | ------------------------------------------------------------- |
|
||||
| `"native"` | The native HTML anchor element that wraps all child elements. |
|
||||
|
||||
|
||||
## CSS Custom Properties
|
||||
|
||||
| Name | Description |
|
||||
|
||||
@@ -7,6 +7,8 @@ import { AnchorInterface } from '../../utils/element-interface';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
*
|
||||
* @part native - The native HTML anchor element that wraps all child elements.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-tab-button',
|
||||
@@ -161,7 +163,7 @@ export class TabButton implements ComponentInterface, AnchorInterface {
|
||||
'ion-focusable': true
|
||||
}}
|
||||
>
|
||||
<a {...attrs} tabIndex={-1} class="button-native">
|
||||
<a {...attrs} tabIndex={-1} class="button-native" part="native">
|
||||
<span class="button-inner">
|
||||
<slot></slot>
|
||||
</span>
|
||||
|
||||
@@ -345,7 +345,7 @@ export class Textarea implements ComponentInterface {
|
||||
placeholder={this.placeholder || ''}
|
||||
readOnly={this.readonly}
|
||||
required={this.required}
|
||||
spellcheck={this.spellcheck ? 'true' : undefined}
|
||||
spellcheck={this.spellcheck}
|
||||
cols={this.cols}
|
||||
rows={this.rows}
|
||||
wrap={this.wrap}
|
||||
|
||||
@@ -256,7 +256,6 @@ export class Toast implements ComponentInterface, OverlayInterface {
|
||||
const mode = getIonMode(this);
|
||||
const wrapperClass = {
|
||||
'toast-wrapper': true,
|
||||
'ion-wrapper': true,
|
||||
[`toast-${this.position}`]: true
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ export const createButtonActiveGesture = (
|
||||
el: HTMLElement,
|
||||
isButton: (refEl: HTMLElement) => boolean
|
||||
): Gesture => {
|
||||
let touchedButton: HTMLElement | undefined;
|
||||
let currentTouchedButton: HTMLElement | undefined;
|
||||
let initialTouchedButton: HTMLElement | undefined;
|
||||
|
||||
const activateButtonAtPoint = (x: number, y: number, hapticFeedbackFn: () => void) => {
|
||||
if (typeof (document as any) === 'undefined') { return; }
|
||||
@@ -18,30 +19,43 @@ export const createButtonActiveGesture = (
|
||||
return;
|
||||
}
|
||||
|
||||
if (target !== touchedButton) {
|
||||
if (target !== currentTouchedButton) {
|
||||
clearActiveButton();
|
||||
setActiveButton(target, hapticFeedbackFn);
|
||||
}
|
||||
};
|
||||
|
||||
const setActiveButton = (button: HTMLElement, hapticFeedbackFn: () => void) => {
|
||||
touchedButton = button;
|
||||
const buttonToModify = touchedButton;
|
||||
currentTouchedButton = button;
|
||||
|
||||
if (!initialTouchedButton) {
|
||||
initialTouchedButton = currentTouchedButton;
|
||||
}
|
||||
|
||||
const buttonToModify = currentTouchedButton;
|
||||
writeTask(() => buttonToModify.classList.add('ion-activated'));
|
||||
hapticFeedbackFn();
|
||||
};
|
||||
|
||||
const clearActiveButton = (dispatchClick = false) => {
|
||||
if (!touchedButton) { return; }
|
||||
if (!currentTouchedButton) { return; }
|
||||
|
||||
const buttonToModify = touchedButton;
|
||||
const buttonToModify = currentTouchedButton;
|
||||
writeTask(() => buttonToModify.classList.remove('ion-activated'));
|
||||
|
||||
if (dispatchClick) {
|
||||
touchedButton.click();
|
||||
/**
|
||||
* Clicking on one button, but releasing on another button
|
||||
* does not dispatch a click event in browsers, so we
|
||||
* need to do it manually here. Some browsers will
|
||||
* dispatch a click if clicking on one button, dragging over
|
||||
* another button, and releasing on the original button. In that
|
||||
* case, we need to make sure we do not cause a double click there.
|
||||
*/
|
||||
if (dispatchClick && initialTouchedButton !== currentTouchedButton) {
|
||||
currentTouchedButton.click();
|
||||
}
|
||||
|
||||
touchedButton = undefined;
|
||||
currentTouchedButton = undefined;
|
||||
};
|
||||
|
||||
return createGesture({
|
||||
@@ -53,6 +67,7 @@ export const createButtonActiveGesture = (
|
||||
onEnd: () => {
|
||||
clearActiveButton(true);
|
||||
hapticSelectionEnd();
|
||||
initialTouchedButton = undefined;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Color, CssClassMap, RouterDirection } from '../interface';
|
||||
import { AnimationBuilder, Color, CssClassMap, RouterDirection } from '../interface';
|
||||
|
||||
export const hostContext = (selector: string, el: HTMLElement): boolean => {
|
||||
return el.closest(selector) !== null;
|
||||
@@ -33,14 +33,14 @@ export const getClassMap = (classes: string | string[] | undefined): CssClassMap
|
||||
|
||||
const SCHEME = /^[a-z][a-z0-9+\-.]*:/;
|
||||
|
||||
export const openURL = async (url: string | undefined | null, ev: Event | undefined | null, direction: RouterDirection): Promise<boolean> => {
|
||||
export const openURL = async (url: string | undefined | null, ev: Event | undefined | null, direction: RouterDirection, animation?: AnimationBuilder): Promise<boolean> => {
|
||||
if (url != null && url[0] !== '#' && !SCHEME.test(url)) {
|
||||
const router = document.querySelector('ion-router');
|
||||
if (router) {
|
||||
if (ev != null) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
return router.push(url, direction);
|
||||
return router.push(url, direction, animation);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -363,7 +363,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio
|
||||
|
||||
const translucentHeader = parentHeader?.translucent;
|
||||
if (!translucentHeader) {
|
||||
enteringToolBarBg.fromTo(OPACITY, 0.01, 1);
|
||||
enteringToolBarBg.fromTo(OPACITY, 0.01, 'var(--opacity)');
|
||||
} else {
|
||||
enteringToolBarBg.fromTo('transform', (isRTL ? 'translateX(-100%)' : 'translateX(100%)'), 'translateX(0px)');
|
||||
}
|
||||
@@ -510,7 +510,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio
|
||||
// should just slide out, no fading out
|
||||
const translucentHeader = parentHeader?.translucent;
|
||||
if (!translucentHeader) {
|
||||
leavingToolBarBg.fromTo(OPACITY, 0.99, 0);
|
||||
leavingToolBarBg.fromTo(OPACITY, 'var(--opacity)', 0);
|
||||
} else {
|
||||
leavingToolBarBg.fromTo('transform', 'translateX(0px)', (isRTL ? 'translateX(-100%)' : 'translateX(100%)'));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -49,7 +49,7 @@
|
||||
"@angular/core": "8.2.13",
|
||||
"@angular/platform-browser": "8.2.13",
|
||||
"@angular/platform-server": "8.2.13",
|
||||
"@ionic/core": "5.1.1",
|
||||
"@ionic/core": "5.2.2",
|
||||
"ng-packagr": "5.7.1",
|
||||
"tslint": "^5.12.1",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
plugins: ['@ionic'],
|
||||
extends: ['plugin:@ionic/strict'],
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"no-negated-condition": 0,
|
||||
"no-conditional-assignment": 0,
|
||||
"no-non-null-assertion": 0,
|
||||
"no-unnecessary-type-assertion": 0,
|
||||
"no-import-side-effect": 0,
|
||||
"trailing-comma": 0,
|
||||
"no-null-keyword": 0,
|
||||
"no-console": 0,
|
||||
"no-floating-promises": 0,
|
||||
|
||||
"jsx-key": 0,
|
||||
"jsx-self-close": 0,
|
||||
"jsx-no-bind": 0,
|
||||
"jsx-no-lambda": 0,
|
||||
"jsx-no-multiline-js": 0,
|
||||
"jsx-wrap-multiline": 0
|
||||
}
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
package-lock=false
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"name": "@ionic/motion",
|
||||
"version": "0.0.1",
|
||||
"description": "Motion animations for Ionic Framework",
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist",
|
||||
"build": "npm run clean && tsc -p . && cp package.json ./dist/package.json",
|
||||
"lint": "eslint src/**/*",
|
||||
"lint.fix": "npm run lint -- --fix"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ionic-team/ionic.git"
|
||||
},
|
||||
"keywords": [
|
||||
"ionic",
|
||||
"framework",
|
||||
"react",
|
||||
"angular",
|
||||
"mobile",
|
||||
"app",
|
||||
"hybrid",
|
||||
"webapp",
|
||||
"cordova",
|
||||
"capacitor",
|
||||
"progressive",
|
||||
"web",
|
||||
"app",
|
||||
"pwa"
|
||||
],
|
||||
"author": "Ionic Team",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ionic-team/ionic/issues"
|
||||
},
|
||||
"homepage": "https://ionicframework.com/",
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-plugin": "0.0.1",
|
||||
"@typescript-eslint/parser": "^2.33.0",
|
||||
"eslint": "^7.0.0",
|
||||
"typescript": "^3.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^5.1.1"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
# @ionic/motion
|
||||
@@ -1,175 +0,0 @@
|
||||
import { Animation, AnimationBuilder, createAnimation } from '@ionic/core';
|
||||
import { AnimationOptions, Axis } from '../';
|
||||
|
||||
const createXAxisTransition = (enteringEl: HTMLElement, leavingEl: HTMLElement, backDirection: boolean): Animation[] => {
|
||||
const enteringTransition = createAnimation().addElement(enteringEl);
|
||||
const leavingTransition = createAnimation().addElement(leavingEl);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'translate3d(-30px, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'translate3d(30px, 0, 0)' },
|
||||
]);
|
||||
} else {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'translate3d(30px, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'translate3d(-30px, 0, 0)' },
|
||||
]);
|
||||
}
|
||||
|
||||
return [enteringTransition, leavingTransition];
|
||||
};
|
||||
const createYAxisTransition = (enteringEl: HTMLElement, leavingEl: HTMLElement, backDirection: boolean): Animation[] => {
|
||||
const enteringTransition = createAnimation().addElement(enteringEl);
|
||||
const leavingTransition = createAnimation().addElement(leavingEl);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'translate3d(0, -30px, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'translate3d(0, 30px, 0)' },
|
||||
]);
|
||||
} else {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'translate3d(0, 30px, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'translate3d(0, 0, 0)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'translate3d(0, -30px, 0)' },
|
||||
]);
|
||||
}
|
||||
|
||||
return [enteringTransition, leavingTransition];
|
||||
};
|
||||
const createFadeZAxisTransition = (enteringEl: HTMLElement, leavingEl: HTMLElement, backDirection: boolean): Animation[] => {
|
||||
const enteringTransition = createAnimation().addElement(enteringEl);
|
||||
const leavingTransition = createAnimation().addElement(leavingEl);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale3d(1.1, 1.1, 1)' },
|
||||
{ offset: 1, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
{ offset: 0.2, opacity: 1 },
|
||||
{ offset: 0.4, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'scale3d(0.8, 0.8, 1)' },
|
||||
]);
|
||||
} else {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale3d(0.8, 0.8, 1)' },
|
||||
{ offset: 0.2, opacity: 0 },
|
||||
{ offset: 0.4, opacity: 1 },
|
||||
{ offset: 1, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, transform: 'scale3d(1, 1, 1)' },
|
||||
{ offset: 1, transform: 'scale3d(1.1, 1.1, 1)' },
|
||||
]);
|
||||
}
|
||||
|
||||
return [enteringTransition, leavingTransition];
|
||||
};
|
||||
const createNormalZAxisTransition = (enteringEl: HTMLElement, leavingEl: HTMLElement, backDirection: boolean): Animation[] => {
|
||||
const enteringTransition = createAnimation().addElement(enteringEl);
|
||||
const leavingTransition = createAnimation().addElement(leavingEl);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale3d(1.1, 1.1, 1)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'scale3d(0.8, 0.8, 1)' },
|
||||
]);
|
||||
} else {
|
||||
enteringTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale3d(0.8, 0.8, 1)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
]);
|
||||
|
||||
leavingTransition
|
||||
.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'scale3d(1, 1, 1)' },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0, transform: 'scale3d(1.1, 1.1, 1)' },
|
||||
]);
|
||||
}
|
||||
|
||||
return [enteringTransition, leavingTransition];
|
||||
};
|
||||
const createZAxisTransition = (enteringEl: HTMLElement, leavingEl: HTMLElement, fade: boolean, backDirection: boolean): Animation[] => fade ? createFadeZAxisTransition(enteringEl, leavingEl, backDirection) : createNormalZAxisTransition(enteringEl, leavingEl, backDirection);
|
||||
|
||||
export const sharedAxisTransition = (axis: Axis = 'z', fade: boolean = false, animationOpts: AnimationOptions = {}): AnimationBuilder => {
|
||||
const { duration, easing } = animationOpts;
|
||||
|
||||
return (_: HTMLElement, opts: any): Animation => {
|
||||
const backDirection = opts.direction === 'back';
|
||||
const { enteringEl, leavingEl } = opts;
|
||||
|
||||
const baseTransition = createAnimation()
|
||||
.duration(duration !== undefined ? duration : 300)
|
||||
.easing(easing || 'ease');
|
||||
|
||||
switch (axis) {
|
||||
case 'x':
|
||||
baseTransition.addAnimation(createXAxisTransition(enteringEl, leavingEl, backDirection));
|
||||
break;
|
||||
case 'y':
|
||||
baseTransition.addAnimation(createYAxisTransition(enteringEl, leavingEl, backDirection));
|
||||
break;
|
||||
default:
|
||||
baseTransition.addAnimation(createZAxisTransition(enteringEl, leavingEl, fade, backDirection));
|
||||
break;
|
||||
}
|
||||
|
||||
return baseTransition;
|
||||
};
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
import { AnimationOptions } from '../';
|
||||
import { Animation, AnimationBuilder, createAnimation } from '@ionic/core';
|
||||
|
||||
const createBase = (animationOpts: AnimationOptions, enteringEl: HTMLElement, leavingEl: HTMLElement): { [key: string]: Animation; } => {
|
||||
const { duration, easing } = animationOpts;
|
||||
const rootAnimation = createAnimation()
|
||||
.duration(duration !== undefined ? duration : 300)
|
||||
.easing(easing || 'ease');
|
||||
|
||||
const leavingAnimation = createAnimation().addElement(leavingEl);
|
||||
const enteringAnimation = createAnimation().addElement(enteringEl);
|
||||
|
||||
rootAnimation.addAnimation([leavingAnimation, enteringAnimation]);
|
||||
|
||||
return { rootAnimation, enteringAnimation, leavingAnimation };
|
||||
};
|
||||
|
||||
const enter = (animationOpts: AnimationOptions, enteringEl: HTMLElement, leavingEl: HTMLElement): Animation => {
|
||||
const { rootAnimation, enteringAnimation, leavingAnimation } = createBase(animationOpts, enteringEl, leavingEl);
|
||||
|
||||
leavingAnimation.keyframes([
|
||||
{ offset: 0, opacity: 1 },
|
||||
{ offset: 0.3, opacity: 0 },
|
||||
{ offset: 1, opacity: 0 },
|
||||
]);
|
||||
|
||||
enteringAnimation.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale(0.92)' },
|
||||
{ offset: 0.3, opacity: 0, transform: 'scale(0.92)' },
|
||||
{ offset: 1, opacity: 1, transform: 'scale(1)' },
|
||||
]);
|
||||
|
||||
return rootAnimation;
|
||||
};
|
||||
|
||||
const leave = (animationOpts: AnimationOptions, enteringEl: HTMLElement, leavingEl: HTMLElement): Animation => {
|
||||
const { rootAnimation, enteringAnimation, leavingAnimation } = createBase(animationOpts, enteringEl, leavingEl);
|
||||
|
||||
leavingAnimation.keyframes([
|
||||
{ offset: 0, opacity: 1, transform: 'scale(1)' },
|
||||
{ offset: 0.7, opacity: 0, transform: 'scale(0.92)' },
|
||||
{ offset: 1, opacity: 0, transform: 'scale(0.92)' },
|
||||
]);
|
||||
|
||||
enteringAnimation.keyframes([
|
||||
{ offset: 0, opacity: 0 },
|
||||
{ offset: 0.7, opacity: 0 },
|
||||
{ offset: 1, opacity: 1 },
|
||||
]);
|
||||
|
||||
return rootAnimation;
|
||||
};
|
||||
|
||||
export const fadeThroughMotionEnter = (presentingEl: HTMLElement, animationOpts: AnimationOptions = {}): AnimationBuilder => (baseEl: HTMLElement): Animation => enter(animationOpts, baseEl, presentingEl);
|
||||
|
||||
export const fadeThroughMotionLeave = (presentingEl: HTMLElement, animationOpts: AnimationOptions = {}): AnimationBuilder => (baseEl: HTMLElement): Animation => leave(animationOpts, presentingEl, baseEl);
|
||||
|
||||
export const fadeThroughMotion = (animationOpts: AnimationOptions = {}): AnimationBuilder => (_: HTMLElement, opts: any): Animation => {
|
||||
const backDirection = opts.direction === 'back';
|
||||
const { enteringEl, leavingEl } = opts;
|
||||
|
||||
return backDirection ? leave(animationOpts, enteringEl, leavingEl) : enter(animationOpts, enteringEl, leavingEl);
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import { AnimationOptions } from '../';
|
||||
import { getElementRoot } from '../utils';
|
||||
import { Animation, AnimationBuilder, createAnimation } from '@ionic/core';
|
||||
|
||||
const createBase = (animationOpts: AnimationOptions, enteringEl: HTMLElement): { [key: string]: Animation; } => {
|
||||
const { duration, easing } = animationOpts;
|
||||
const rootAnimation = createAnimation()
|
||||
.duration(duration !== undefined ? duration : 150)
|
||||
.easing(easing || 'ease');
|
||||
|
||||
const elementAnimation = createAnimation().addElement(enteringEl);
|
||||
|
||||
rootAnimation.addAnimation([elementAnimation]);
|
||||
|
||||
return { rootAnimation, elementAnimation };
|
||||
};
|
||||
|
||||
const enter = (animationOpts: AnimationOptions, baseEl: HTMLElement): Animation => {
|
||||
const root = getElementRoot(baseEl);
|
||||
const wrapper = (root.querySelector('.ion-wrapper') || baseEl) as HTMLElement;
|
||||
const backdrop = root.querySelector('ion-backdrop');
|
||||
const { rootAnimation, elementAnimation } = createBase(animationOpts, wrapper);
|
||||
|
||||
elementAnimation.keyframes([
|
||||
{ offset: 0, opacity: 0, transform: 'scale(0.8)' },
|
||||
{ offset: 0.3, opacity: 1 },
|
||||
{ offset: 1, opacity: 1, transform: 'scale(1)' },
|
||||
]);
|
||||
|
||||
if (backdrop) {
|
||||
const backdropAnimation = createAnimation()
|
||||
.addElement(backdrop)
|
||||
.fromTo('opacity', '0', 'var(--backdrop-opacity, 1)');
|
||||
|
||||
rootAnimation.addAnimation(backdropAnimation);
|
||||
}
|
||||
|
||||
return rootAnimation;
|
||||
};
|
||||
|
||||
const leave = (animationOpts: AnimationOptions, baseEl: HTMLElement): Animation => {
|
||||
const root = getElementRoot(baseEl);
|
||||
const wrapper = (root.querySelector('.ion-wrapper') || baseEl) as HTMLElement;
|
||||
const backdrop = root.querySelector('ion-backdrop');
|
||||
const { rootAnimation, elementAnimation } = createBase(animationOpts, wrapper);
|
||||
|
||||
elementAnimation.keyframes([
|
||||
{ offset: 0, opacity: 1 },
|
||||
{ offset: 1, opacity: 0 },
|
||||
]);
|
||||
|
||||
if (backdrop) {
|
||||
const backdropAnimation = createAnimation()
|
||||
.addElement(backdrop)
|
||||
.fromTo('opacity', 'var(--backdrop-opacity, 1)', '0');
|
||||
|
||||
rootAnimation.addAnimation(backdropAnimation);
|
||||
}
|
||||
|
||||
return rootAnimation;
|
||||
};
|
||||
|
||||
export const fadeMotionEnter = (animationOpts: AnimationOptions = {}): AnimationBuilder => (baseEl: HTMLElement): Animation => enter(animationOpts, baseEl);
|
||||
|
||||
export const fadeMotionLeave = (animationOpts: AnimationOptions = {}): AnimationBuilder => (baseEl: HTMLElement): Animation => leave(animationOpts, baseEl);
|
||||
|
||||
export const fadeMotion = (animationOpts: AnimationOptions = {}): AnimationBuilder => (_: HTMLElement, opts: any): Animation => {
|
||||
const backDirection = opts.direction === 'back';
|
||||
const { enteringEl, leavingEl } = opts;
|
||||
|
||||
return backDirection ? leave(animationOpts, leavingEl) : enter(animationOpts, enteringEl);
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
export { sharedAxisTransition } from './animations/axis.motion';
|
||||
export { fadeMotion, fadeMotionEnter, fadeMotionLeave } from './animations/fade.motion';
|
||||
export { fadeThroughMotion, fadeThroughMotionEnter, fadeThroughMotionLeave } from './animations/fade-through.motion';
|
||||
|
||||
export interface AnimationOptions {
|
||||
duration?: number;
|
||||
easing?: string;
|
||||
}
|
||||
|
||||
export type Axis = 'x' | 'y' | 'z';
|
||||
@@ -1 +0,0 @@
|
||||
export const getElementRoot = (el: HTMLElement, fallback: HTMLElement = el) => el.shadowRoot || fallback;
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowUnreachableCode": false,
|
||||
"declaration": true,
|
||||
"experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"assumeChangesOnlyAffectDirectDependencies": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2017"
|
||||
],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"outDir": "dist",
|
||||
"pretty": true,
|
||||
"removeComments": false,
|
||||
"target": "es2017"
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/test"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "React Router wrapper for @ionic/react",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -39,16 +39,16 @@
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ionic/core": "5.1.1",
|
||||
"@ionic/react": "5.1.1",
|
||||
"@ionic/core": "5.2.2",
|
||||
"@ionic/react": "5.2.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/core": "5.1.1",
|
||||
"@ionic/react": "5.1.1",
|
||||
"@ionic/core": "5.2.2",
|
||||
"@ionic/react": "5.2.2",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "5.1.1",
|
||||
"version": "5.2.2",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -39,7 +39,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "5.1.1",
|
||||
"@ionic/core": "5.2.2",
|
||||
"ionicons": "^5.0.1",
|
||||
"tslib": "*"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user