mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 09:34:19 +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) {
|
||||
const el = r.nativeElement;
|
||||
proxyMethods(this, el, ['complete', 'waitFor']);
|
||||
proxyMethods(this, el, ['complete']);
|
||||
proxyInputs(this, el, ['threshold', 'disabled', 'position']);
|
||||
proxyOutputs(this, el, ['ionInfinite']);
|
||||
}
|
||||
@ -640,13 +640,12 @@ export class ReorderGroup {
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
constructor(r: ElementRef) {
|
||||
const el = r.nativeElement;
|
||||
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
|
||||
*/
|
||||
'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 {
|
||||
/**
|
||||
|
@ -333,7 +333,7 @@ export class Alert implements OverlayInterface {
|
||||
{i.label}
|
||||
</div>
|
||||
</div>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@ -362,7 +362,7 @@ export class Alert implements OverlayInterface {
|
||||
{i.label}
|
||||
</div>
|
||||
</div>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
@ -83,7 +83,7 @@ export class BackButton {
|
||||
<span class="back-button-inner">
|
||||
{ backButtonIcon && <ion-icon icon={backButtonIcon} lazy={false}/> }
|
||||
{ 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>
|
||||
</button>
|
||||
);
|
||||
|
@ -183,7 +183,7 @@ export class Button {
|
||||
<slot></slot>
|
||||
<slot name="end"></slot>
|
||||
</span>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el} /> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</TagType>
|
||||
);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ export class ChipButton {
|
||||
<span class="chip-button-inner">
|
||||
<slot></slot>
|
||||
</span>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</TagType>
|
||||
);
|
||||
}
|
||||
|
@ -537,7 +537,7 @@ export class Datetime {
|
||||
aria-disabled={this.disabled ? 'true' : null}
|
||||
onClick={this.open.bind(this)}
|
||||
class="datetime-cover">
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</button>
|
||||
];
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ export class FabButton {
|
||||
<span class="fab-button-inner">
|
||||
<slot></slot>
|
||||
</span>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</TagType>
|
||||
);
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ Separating the `ion-infinite-scroll` and `ion-infinite-scroll-content` component
|
||||
| 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`. |
|
||||
| `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() {
|
||||
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 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> }
|
||||
</div>
|
||||
{ state && <div class="item-state"></div> }
|
||||
{ clickable && mode === 'md' && <ion-ripple-effect tapClick={true} parent={el} /> }
|
||||
{ clickable && mode === 'md' && <ion-ripple-effect /> }
|
||||
</TagType>
|
||||
);
|
||||
}
|
||||
|
@ -6,14 +6,6 @@ The ripple effect component adds the [Material Design ink ripple interaction eff
|
||||
<!-- 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
|
||||
|
||||
| Method | Description |
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { Component, Element, EventListenerEnable, Listen, Method, Prop, QueueApi, Watch } from '@stencil/core';
|
||||
|
||||
import { now } from '../../utils/helpers';
|
||||
import { Component, Element, Method, Prop, QueueApi } from '@stencil/core';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-ripple-effect',
|
||||
@ -9,48 +7,11 @@ import { now } from '../../utils/helpers';
|
||||
})
|
||||
export class RippleEffect {
|
||||
|
||||
private lastClick = -10000;
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'enableListener' }) enableListener!: EventListenerEnable;
|
||||
@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
|
||||
*/
|
||||
|
@ -75,7 +75,7 @@ export class SegmentButton {
|
||||
disabled={this.disabled}
|
||||
onClick={() => this.checked = true }>
|
||||
<slot></slot>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true} parent={this.el}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</button>
|
||||
];
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ export class Select {
|
||||
onBlur={this.onBlur.bind(this)}
|
||||
class="select-cover">
|
||||
<slot></slot>
|
||||
{ this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
|
||||
{ this.mode === 'md' && <ion-ripple-effect /> }
|
||||
</button>
|
||||
];
|
||||
}
|
||||
|
@ -130,13 +130,12 @@ export class Tabbar {
|
||||
if (!tab.disabled) {
|
||||
this.ionTabbarClick.emit(tab);
|
||||
}
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
}}>
|
||||
{ icon && <ion-icon class="tab-btn-icon" icon={icon} lazy={false}></ion-icon> }
|
||||
{ label && <span class="tab-btn-text">{label}</span> }
|
||||
{ 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>
|
||||
);
|
||||
}
|
||||
|
@ -109,11 +109,10 @@ export function startTapClick(doc: Document) {
|
||||
lastActivated = Date.now();
|
||||
el.classList.add(ACTIVATED);
|
||||
|
||||
const event = new CustomEvent('ionActivated', {
|
||||
bubbles: false,
|
||||
detail: { x, y }
|
||||
});
|
||||
el.dispatchEvent(event);
|
||||
const rippleEffect = getRippleEffect(el);
|
||||
if (rippleEffect && rippleEffect.addRipple) {
|
||||
rippleEffect.addRipple(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
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 ADD_ACTIVATED_DEFERS = 200;
|
||||
const CLEAR_STATE_DEFERS = 200;
|
||||
|
Reference in New Issue
Block a user