mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 17:42:15 +08:00
fix(ripple-effect): using method invocation instead of events
fixes #15318
This commit is contained in:
@ -340,7 +340,7 @@ export class InfiniteScroll {
|
|||||||
|
|
||||||
constructor(r: ElementRef) {
|
constructor(r: ElementRef) {
|
||||||
const el = r.nativeElement;
|
const el = r.nativeElement;
|
||||||
proxyMethods(this, el, ['complete', 'waitFor']);
|
proxyMethods(this, el, ['complete']);
|
||||||
proxyInputs(this, el, ['threshold', 'disabled', 'position']);
|
proxyInputs(this, el, ['threshold', 'disabled', 'position']);
|
||||||
proxyOutputs(this, el, ['ionInfinite']);
|
proxyOutputs(this, el, ['ionInfinite']);
|
||||||
}
|
}
|
||||||
@ -640,13 +640,12 @@ export class ReorderGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export declare interface RippleEffect extends Promisify<StencilComponents<'IonRippleEffect'>> {}
|
export declare interface RippleEffect extends Promisify<StencilComponents<'IonRippleEffect'>> {}
|
||||||
@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['parent', 'tapClick'] })
|
@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>' })
|
||||||
export class RippleEffect {
|
export class RippleEffect {
|
||||||
|
|
||||||
constructor(r: ElementRef) {
|
constructor(r: ElementRef) {
|
||||||
const el = r.nativeElement;
|
const el = r.nativeElement;
|
||||||
proxyMethods(this, el, ['addRipple']);
|
proxyMethods(this, el, ['addRipple']);
|
||||||
proxyInputs(this, el, ['parent', 'tapClick']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
core/src/components.d.ts
vendored
13
core/src/components.d.ts
vendored
@ -3517,19 +3517,8 @@ export namespace Components {
|
|||||||
* Adds the ripple effect to the parent element
|
* Adds the ripple effect to the parent element
|
||||||
*/
|
*/
|
||||||
'addRipple': (pageX: number, pageY: number) => void;
|
'addRipple': (pageX: number, pageY: number) => void;
|
||||||
'parent': HTMLElement | string;
|
|
||||||
/**
|
|
||||||
* If true, the ripple effect will listen to any click events and animate
|
|
||||||
*/
|
|
||||||
'tapClick': boolean;
|
|
||||||
}
|
|
||||||
interface IonRippleEffectAttributes extends StencilHTMLAttributes {
|
|
||||||
'parent'?: HTMLElement | string;
|
|
||||||
/**
|
|
||||||
* If true, the ripple effect will listen to any click events and animate
|
|
||||||
*/
|
|
||||||
'tapClick'?: boolean;
|
|
||||||
}
|
}
|
||||||
|
interface IonRippleEffectAttributes extends StencilHTMLAttributes {}
|
||||||
|
|
||||||
interface IonRouteRedirect {
|
interface IonRouteRedirect {
|
||||||
/**
|
/**
|
||||||
|
@ -333,7 +333,7 @@ export class Alert implements OverlayInterface {
|
|||||||
{i.label}
|
{i.label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -362,7 +362,7 @@ export class Alert implements OverlayInterface {
|
|||||||
{i.label}
|
{i.label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,7 +83,7 @@ export class BackButton {
|
|||||||
<span class="back-button-inner">
|
<span class="back-button-inner">
|
||||||
{ backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false}/> }
|
{ backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false}/> }
|
||||||
{ this.mode === 'ios' && backButtonText && <span class="button-text">{backButtonText}</span> }
|
{ this.mode === 'ios' && backButtonText && <span class="button-text">{backButtonText}</span> }
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
@ -183,7 +183,7 @@ export class Button {
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
<slot name="end"></slot>
|
<slot name="end"></slot>
|
||||||
</span>
|
</span>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el} /> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</TagType>
|
</TagType>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ export class ChipButton {
|
|||||||
<span class="chip-button-inner">
|
<span class="chip-button-inner">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</span>
|
</span>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</TagType>
|
</TagType>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -537,7 +537,7 @@ export class Datetime {
|
|||||||
aria-disabled={this.disabled ? 'true' : null}
|
aria-disabled={this.disabled ? 'true' : null}
|
||||||
onClick={this.open.bind(this)}
|
onClick={this.open.bind(this)}
|
||||||
class="datetime-cover">
|
class="datetime-cover">
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</button>
|
</button>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ export class FabButton {
|
|||||||
<span class="fab-button-inner">
|
<span class="fab-button-inner">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</span>
|
</span>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</TagType>
|
</TagType>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ Separating the `ion-infinite-scroll` and `ion-infinite-scroll-content` component
|
|||||||
| Method | Description |
|
| Method | Description |
|
||||||
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `complete` | Call `complete()` within the `infinite` output event handler when your async operation has completed. For example, the `loading` state is while the app is performing an asynchronous operation, such as receiving more data from an AJAX request to add more items to a data list. Once the data has been received and UI updated, you then call this method to signify that the loading has completed. This method will change the infinite scroll's state from `loading` to `enabled`. |
|
| `complete` | Call `complete()` within the `infinite` output event handler when your async operation has completed. For example, the `loading` state is while the app is performing an asynchronous operation, such as receiving more data from an AJAX request to add more items to a data list. Once the data has been received and UI updated, you then call this method to signify that the loading has completed. This method will change the infinite scroll's state from `loading` to `enabled`. |
|
||||||
| `waitFor` | Pass a promise inside `waitFor()` within the `infinite` output event handler in order to change state of infiniteScroll to "complete" |
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
@ -139,7 +139,7 @@ export class Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { href, detail, mode, win, state, detailIcon, el, routerDirection, type } = this;
|
const { href, detail, mode, win, state, detailIcon, routerDirection, type } = this;
|
||||||
|
|
||||||
const clickable = this.isClickable();
|
const clickable = this.isClickable();
|
||||||
const TagType = clickable ? (href ? 'a' : 'button') : 'div';
|
const TagType = clickable ? (href ? 'a' : 'button') : 'div';
|
||||||
@ -161,7 +161,7 @@ export class Item {
|
|||||||
{ showDetail && <ion-icon icon={detailIcon} lazy={false} class="item-detail-icon"></ion-icon> }
|
{ showDetail && <ion-icon icon={detailIcon} lazy={false} class="item-detail-icon"></ion-icon> }
|
||||||
</div>
|
</div>
|
||||||
{ state && <div class="item-state"></div> }
|
{ state && <div class="item-state"></div> }
|
||||||
{ clickable && mode === 'md' && <ion-ripple-effect tapClick={true} parent={el} /> }
|
{ clickable && mode === 'md' && <ion-ripple-effect /> }
|
||||||
</TagType>
|
</TagType>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,6 @@ The ripple effect component adds the [Material Design ink ripple interaction eff
|
|||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Attribute | Description | Type |
|
|
||||||
| ---------- | ----------- | ---------------------------------------------------------------------- | ----------------------- |
|
|
||||||
| `parent` | `parent` | | `HTMLElement`, `string` |
|
|
||||||
| `tapClick` | `tap-click` | If true, the ripple effect will listen to any click events and animate | `boolean` |
|
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
| Method | Description |
|
| Method | Description |
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
import { Component, Element, Method, Prop, QueueApi } from '@stencil/core';
|
||||||
|
|
||||||
import { now } from '../../utils/helpers';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-ripple-effect',
|
tag: 'ion-ripple-effect',
|
||||||
@ -9,48 +7,11 @@ import { now } from '../../utils/helpers';
|
|||||||
})
|
})
|
||||||
export class RippleEffect {
|
export class RippleEffect {
|
||||||
|
|
||||||
private lastClick = -10000;
|
|
||||||
@Element() el!: HTMLElement;
|
@Element() el!: HTMLElement;
|
||||||
|
|
||||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||||
@Prop({ context: 'enableListener' }) enableListener!: EventListenerEnable;
|
|
||||||
@Prop({ context: 'window' }) win!: Window;
|
@Prop({ context: 'window' }) win!: Window;
|
||||||
|
|
||||||
@Prop() parent?: HTMLElement | string = 'parent';
|
|
||||||
|
|
||||||
/** If true, the ripple effect will listen to any click events and animate */
|
|
||||||
@Prop() tapClick = false;
|
|
||||||
@Watch('tapClick')
|
|
||||||
tapClickChanged(tapClick: boolean) {
|
|
||||||
this.enableListener(this, 'ionActivated', tapClick, this.parent);
|
|
||||||
this.enableListener(this, 'touchstart', !tapClick);
|
|
||||||
this.enableListener(this, 'mousedown', !tapClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listen('ionActivated', { enabled: false })
|
|
||||||
ionActivated(ev: CustomEvent) {
|
|
||||||
this.addRipple(ev.detail.x, ev.detail.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listen('touchstart', { passive: true, enabled: false })
|
|
||||||
touchStart(ev: TouchEvent) {
|
|
||||||
this.lastClick = now(ev);
|
|
||||||
const touches = ev.touches[0];
|
|
||||||
this.addRipple(touches.clientX, touches.clientY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listen('mousedown', { passive: true, enabled: false })
|
|
||||||
mouseDown(ev: MouseEvent) {
|
|
||||||
const timeStamp = now(ev);
|
|
||||||
if (this.lastClick < (timeStamp - 1000)) {
|
|
||||||
this.addRipple(ev.pageX, ev.pageY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidLoad() {
|
|
||||||
this.tapClickChanged(this.tapClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the ripple effect to the parent element
|
* Adds the ripple effect to the parent element
|
||||||
*/
|
*/
|
||||||
|
@ -75,7 +75,7 @@ export class SegmentButton {
|
|||||||
disabled={this.disabled}
|
disabled={this.disabled}
|
||||||
onClick={() => this.checked = true }>
|
onClick={() => this.checked = true }>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</button>
|
</button>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ export class Select {
|
|||||||
onBlur={this.onBlur.bind(this)}
|
onBlur={this.onBlur.bind(this)}
|
||||||
class="select-cover">
|
class="select-cover">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</button>
|
</button>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -130,13 +130,12 @@ export class Tabbar {
|
|||||||
if (!tab.disabled) {
|
if (!tab.disabled) {
|
||||||
this.ionTabbarClick.emit(tab);
|
this.ionTabbarClick.emit(tab);
|
||||||
}
|
}
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}}>
|
}}>
|
||||||
{ icon && <ion-icon class="tab-btn-icon" icon={icon} lazy={false}></ion-icon> }
|
{ icon && <ion-icon class="tab-btn-icon" icon={icon} lazy={false}></ion-icon> }
|
||||||
{ label && <span class="tab-btn-text">{label}</span> }
|
{ label && <span class="tab-btn-text">{label}</span> }
|
||||||
{ badge && <ion-badge class="tab-btn-badge" color={badgeColor}>{badge}</ion-badge> }
|
{ badge && <ion-badge class="tab-btn-badge" color={badgeColor}>{badge}</ion-badge> }
|
||||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}></ion-ripple-effect> }
|
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -109,11 +109,10 @@ export function startTapClick(doc: Document) {
|
|||||||
lastActivated = Date.now();
|
lastActivated = Date.now();
|
||||||
el.classList.add(ACTIVATED);
|
el.classList.add(ACTIVATED);
|
||||||
|
|
||||||
const event = new CustomEvent('ionActivated', {
|
const rippleEffect = getRippleEffect(el);
|
||||||
bubbles: false,
|
if (rippleEffect && rippleEffect.addRipple) {
|
||||||
detail: { x, y }
|
rippleEffect.addRipple(x, y);
|
||||||
});
|
}
|
||||||
el.dispatchEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeActivated(smooth: boolean) {
|
function removeActivated(smooth: boolean) {
|
||||||
@ -159,6 +158,16 @@ function getActivatableTarget(ev: any): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRippleEffect(el: HTMLElement) {
|
||||||
|
if (el.shadowRoot) {
|
||||||
|
const ripple = el.shadowRoot.querySelector('ion-ripple-effect');
|
||||||
|
if (ripple) {
|
||||||
|
return ripple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return el.querySelector('ion-ripple-effect');
|
||||||
|
}
|
||||||
|
|
||||||
const ACTIVATED = 'activated';
|
const ACTIVATED = 'activated';
|
||||||
const ADD_ACTIVATED_DEFERS = 200;
|
const ADD_ACTIVATED_DEFERS = 200;
|
||||||
const CLEAR_STATE_DEFERS = 200;
|
const CLEAR_STATE_DEFERS = 200;
|
||||||
|
Reference in New Issue
Block a user