feat(tapclick): adds tap-click

This commit is contained in:
Manu Mtz.-Almeida
2018-01-20 01:08:35 +01:00
parent 808aff3ebc
commit e5be888c90
25 changed files with 487 additions and 215 deletions

View File

@ -923,36 +923,6 @@ declare global {
}
import {
GestureController as IonGestureController
} from './components/gesture-controller/gesture-controller';
declare global {
interface HTMLIonGestureControllerElement extends IonGestureController, HTMLElement {
}
var HTMLIonGestureControllerElement: {
prototype: HTMLIonGestureControllerElement;
new (): HTMLIonGestureControllerElement;
};
interface HTMLElementTagNameMap {
"ion-gesture-controller": HTMLIonGestureControllerElement;
}
interface ElementTagNameMap {
"ion-gesture-controller": HTMLIonGestureControllerElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-gesture-controller": JSXElements.IonGestureControllerAttributes;
}
}
namespace JSXElements {
export interface IonGestureControllerAttributes extends HTMLAttributes {
}
}
}
import {
Gesture as IonGesture
} from './components/gesture/gesture';
@ -2295,7 +2265,7 @@ declare global {
}
namespace JSXElements {
export interface IonRippleEffectAttributes extends HTMLAttributes {
useTapClick?: boolean;
}
}
}
@ -2449,7 +2419,6 @@ declare global {
namespace JSXElements {
export interface IonScrollAttributes extends HTMLAttributes {
enabled?: boolean;
jsScroll?: boolean;
onionScroll?: ScrollCallback;
onionScrollEnd?: ScrollCallback;
onionScrollStart?: ScrollCallback;
@ -2970,6 +2939,36 @@ declare global {
}
import {
TapClick as IonTapClick
} from './components/tap-click/tap-click';
declare global {
interface HTMLIonTapClickElement extends IonTapClick, HTMLElement {
}
var HTMLIonTapClickElement: {
prototype: HTMLIonTapClickElement;
new (): HTMLIonTapClickElement;
};
interface HTMLElementTagNameMap {
"ion-tap-click": HTMLIonTapClickElement;
}
interface ElementTagNameMap {
"ion-tap-click": HTMLIonTapClickElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-tap-click": JSXElements.IonTapClickAttributes;
}
}
namespace JSXElements {
export interface IonTapClickAttributes extends HTMLAttributes {
}
}
}
import {
Text as IonText
} from './components/text/text';

View File

@ -3,6 +3,7 @@ import { Config, Nav, NavContainer } from '../../index';
import { isReady } from '../../utils/helpers';
const rootNavs = new Map<number, NavContainer>();
const ACTIVE_SCROLLING_TIME = 100;
@Component({
tag: 'ion-app',
@ -16,6 +17,9 @@ const rootNavs = new Map<number, NavContainer>();
})
export class App {
private didScroll = false;
private scrollTime = 0;
@Element() element: HTMLElement;
@State() modeCode: string;
@ -27,7 +31,7 @@ export class App {
componentWillLoad() {
this.modeCode = this.config.get('mode');
this.useRouter = this.config.getBoolean('useRouter', false);
this.hoverCSS = this.config.getBoolean('hoverCSS', true);
this.hoverCSS = this.config.getBoolean('hoverCSS', false);
}
@Listen('body:navInit')
@ -35,7 +39,6 @@ export class App {
rootNavs.set((event.detail as Nav).navId, (event.detail as Nav));
}
/**
* Returns an array of top level Navs
*/
@ -48,16 +51,36 @@ export class App {
return navs;
}
/**
* Check if the app is currently scrolling
*/
@Method() isScrolling(): boolean {
// TODO - sync with Manu
return false;
@Method()
isEnabled(): boolean {
return true;
}
@Method() getActiveNavs(rootNavId?: number): NavContainer[] {
/**
* Boolean if the app is actively scrolling or not.
* @return {boolean} returns true or false
*/
@Method()
isScrolling(): boolean {
const scrollTime = this.scrollTime;
if (scrollTime === 0) {
return false;
}
if (scrollTime < Date.now()) {
this.scrollTime = 0;
return false;
}
return true;
}
@Method()
setScrolling() {
this.scrollTime = Date.now() + ACTIVE_SCROLLING_TIME;
this.didScroll = true;
}
@Method()
getActiveNavs(rootNavId?: number): NavContainer[] {
/*const portal = portals.get(PORTAL_MODAL);
if (portal && portal.views && portal.views.length) {
return findTopNavs(portal);
@ -81,7 +104,8 @@ export class App {
return activeNavs;
}
@Method() getNavByIdOrName(nameOrId: number | string) {
@Method()
getNavByIdOrName(nameOrId: number | string) {
const navs = Array.from(rootNavs.values());
for (const navContainer of navs) {
const match = getNavByIdOrNameImpl(navContainer, nameOrId);
@ -102,8 +126,9 @@ export class App {
}
render() {
const dom = [<slot></slot>];
const dom = [<ion-tap-click />, <slot></slot>];
if (this.useRouter) {
// dom.push(<ion-router-controller></ion-router-controller>);
}
return dom;

View File

@ -18,9 +18,15 @@
Returns an array of top level Navs
#### isEnabled()
#### isScrolling()
Check if the app is currently scrolling
Boolean if the app is actively scrolling or not.
#### setScrolling()

View File

@ -30,7 +30,7 @@
background-color: $button-ios-background-color-focused;
}
.button-ios:hover:not(.disable-hover) {
.enable-hover .button-ios:hover {
opacity: $button-ios-opacity-hover;
}
@ -169,7 +169,7 @@
background-color: $button-ios-clear-background-color-focused;
}
.button-clear-ios:hover:not(.disable-hover) {
.enable-hover .button-clear-ios:hover {
color: $button-ios-clear-text-color-hover;
opacity: $button-ios-clear-opacity-hover;
}
@ -196,7 +196,7 @@
background-color: $bg-color-focused;
}
.button-clear-ios-#{$color-name}:hover:not(.disable-hover) {
.enable-hover .button-clear-ios-#{$color-name}:hover {
color: $fg-color;
}
}

View File

@ -29,7 +29,7 @@
color $button-md-transition-duration $button-md-transition-timing-function;
}
.button-md:hover:not(.disable-hover) {
.enable-hover .button-md:hover {
background-color: $button-md-background-color-hover;
}
@ -61,7 +61,7 @@
background-color: $bg-color;
}
.button-md-#{$color-name}:hover:not(.disable-hover) {
.enable-hover .button-md-#{$color-name}:hover {
background-color: $bg-color;
}
@ -129,7 +129,7 @@
box-shadow: $button-md-outline-box-shadow;
}
.button-outline-md:hover:not(.disable-hover) {
.enable-hover .button-outline-md:hover {
background-color: $button-md-outline-background-color-hover;
}
@ -161,7 +161,7 @@
background-color: $button-md-outline-background-color;
}
.button-outline-md-#{$color-name}:hover:not(.disable-hover) {
.enable-hover .button-outline-md-#{$color-name}:hover {
background-color: $button-md-outline-background-color-hover;
}
@ -199,7 +199,7 @@
background-color: $button-md-clear-background-color-focused;
}
.button-clear-md:hover:not(.disable-hover) {
.enable-hover .button-clear-md:hover {
background-color: $button-md-clear-background-color-hover;
}
@ -230,7 +230,7 @@
background-color: $bg-color-focused;
}
.button-clear-md-#{$color-name}:hover:not(.disable-hover) {
.enable-hover .button-clear-md-#{$color-name}:hover {
color: $fg-color;
}
}

View File

@ -111,18 +111,16 @@ export class Button {
strong
} = this;
const elementClasses: string[] = []
.concat(
getButtonClassList(buttonType, mode),
getClassList(buttonType, expand, mode),
getClassList(buttonType, size, mode),
getClassList(buttonType, round ? 'round' : null, mode),
getClassList(buttonType, strong ? 'strong' : null, mode),
getColorClassList(buttonType, color, fill, mode),
);
const elementClasses = [
...getButtonClassList(buttonType, mode),
...getClassList(buttonType, expand, mode),
...getClassList(buttonType, size, mode),
...getClassList(buttonType, round ? 'round' : null, mode),
...getClassList(buttonType, strong ? 'strong' : null, mode),
...getColorClassList(buttonType, color, fill, mode),
];
const TagType = this.href ? 'a' : 'button';
const buttonClasses = {
...getElementClassObject(this.el.classList),
...getElementClassObject(elementClasses),
@ -143,7 +141,7 @@ export class Button {
<slot></slot>
<slot name='end'></slot>
</span>
{ this.mode === 'md' && <ion-ripple-effect /> }
{ this.mode === 'md' && <ion-ripple-effect useTapClick={true} /> }
</TagType>
);
}

View File

@ -101,7 +101,7 @@ export class ChipButton {
<span class='button-inner'>
<slot></slot>
</span>
{ this.mode === 'md' && <ion-ripple-effect /> }
{ this.mode === 'md' && <ion-ripple-effect useTapClick={true} /> }
</TagType>
);
}

View File

@ -69,11 +69,6 @@ export class Content {
};
}
@Method()
enableJsScroll() {
this.scrollEl.jsScroll = true;
}
/**
* Scroll to the top of the content component.
*

View File

@ -80,9 +80,6 @@ Emitted when the scrolling first starts.
## Methods
#### enableJsScroll()
#### scrollToBottom()
Scroll to the bottom of the content component.

View File

@ -139,7 +139,7 @@ export class FabButton {
<span class='button-inner'>
<slot></slot>
</span>
{ this.mode === 'md' && <ion-ripple-effect /> }
{ this.mode === 'md' && <ion-ripple-effect useTapClick={true} /> }
</TagType>
);
}

View File

@ -1,16 +1,11 @@
import { Component } from '@stencil/core';
@Component({
tag: 'ion-gesture-controller'
})
export class GestureController {
private gestureId = 0;
private requestedStart: { [eventId: number]: number } = {};
private disabledGestures: { [eventName: string]: Set<number> } = {};
private disabledScroll: Set<number> = new Set<number>();
private capturedId: number = null;
private gestureId = 0;
private requestedStart = new Map<number, number>();
private disabledGestures = new Map<string, Set<number>>();
private disabledScroll = new Set<number>();
private capturedId: number = null;
createGesture(gestureName: string, gesturePriority: number, disableScroll: boolean): GestureDelegate {
return new GestureDelegate(this, this.newID(), gestureName, gesturePriority, disableScroll);
@ -29,11 +24,10 @@ export class GestureController {
start(gestureName: string, id: number, priority: number): boolean {
if (!this.canStart(gestureName)) {
delete this.requestedStart[id];
this.requestedStart.delete(id);
return false;
}
this.requestedStart[id] = priority;
this.requestedStart.set(id, priority);
return true;
}
@ -43,22 +37,22 @@ export class GestureController {
}
const requestedStart = this.requestedStart;
let maxPriority = -10000;
for (const gestureID in requestedStart) {
maxPriority = Math.max(maxPriority, requestedStart[gestureID]);
for (const value of requestedStart.values()) {
maxPriority = Math.max(maxPriority, value);
}
if (maxPriority === priority) {
this.capturedId = id;
this.requestedStart = {};
this.requestedStart.clear();
return true;
}
delete requestedStart[id];
requestedStart.delete(id);
return false;
}
release(id: number) {
delete this.requestedStart[id];
this.requestedStart.delete(id);
if (this.capturedId && id === this.capturedId) {
this.capturedId = null;
@ -66,16 +60,16 @@ export class GestureController {
}
disableGesture(gestureName: string, id: number) {
let set = this.disabledGestures[gestureName];
let set = this.disabledGestures.get(gestureName);
if (!set) {
set = new Set<number>();
this.disabledGestures[gestureName] = set;
this.disabledGestures.set(gestureName, set);
}
set.add(id);
}
enableGesture(gestureName: string, id: number) {
const set = this.disabledGestures[gestureName];
const set = this.disabledGestures.get(gestureName);
if (set) {
set.delete(id);
}
@ -121,7 +115,7 @@ export class GestureController {
}
isDisabled(gestureName: string): boolean {
const disabled = this.disabledGestures[gestureName];
const disabled = this.disabledGestures.get(gestureName);
if (disabled && disabled.size > 0) {
return true;
}

View File

@ -99,7 +99,7 @@ export class Item {
</div>
<slot name='end'></slot>
</div>
{ this.href && this.mode === 'md' && <ion-ripple-effect /> }
{ this.href && this.mode === 'md' && <ion-ripple-effect useTapClick={true} /> }
</TagType>
);
}

View File

@ -5,6 +5,25 @@
<!-- Auto Generated Below -->
## Properties
#### useTapClick
boolean
## Attributes
#### useTapClick
boolean
## Methods
#### addRipple()
----------------------------------------------

View File

@ -1,4 +1,4 @@
import { Component, Element, Listen, Prop } from '@stencil/core';
import { Component, Element, EventListenerEnable, Listen, Method, Prop } from '@stencil/core';
import { now } from '../../utils/helpers';
import { DomController } from '../../global/dom-controller';
@ -12,15 +12,23 @@ export class RippleEffect {
@Element() el: HTMLElement;
@Prop({context: 'dom'}) dom: DomController;
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
@Listen('touchstart')
@Prop() useTapClick = false;
@Listen('parent: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')
@Listen('mousedown', {passive: true, enabled: false})
mouseDown(ev: MouseEvent) {
const timeStamp = now(ev);
if (this.lastClick < (timeStamp - 1000)) {
@ -28,7 +36,17 @@ export class RippleEffect {
}
}
private addRipple(pageX: number, pageY: number) {
componentDidLoad() {
if (this.useTapClick) {
this.enableListener(this, 'parent:ionActivated', true);
} else {
this.enableListener(this, 'touchstart', true);
this.enableListener(this, 'mousedown', true);
}
}
@Method()
addRipple(pageX: number, pageY: number) {
let x: number, y: number, size: number;
this.dom.read(() => {

View File

@ -12,11 +12,6 @@
boolean
#### jsScroll
boolean
#### onionScroll
any
@ -39,11 +34,6 @@ any
boolean
#### jsScroll
boolean
#### onionScroll
any

View File

@ -12,10 +12,9 @@ export class Scroll {
private gesture: GestureDelegate;
private positions: number[] = [];
private _l: number;
private _t: number;
private tmr: any;
private queued = false;
private app: HTMLIonAppElement;
isScrolling = false;
detail: ScrollDetail = {};
@ -27,14 +26,6 @@ export class Scroll {
@Prop({ context: 'isServer' }) isServer: boolean;
@Prop() enabled = true;
@Prop() jsScroll = false;
@Watch('jsScroll')
jsScrollChanged(js: boolean) {
if (js) {
throw new Error('jsScroll: TODO!');
}
}
@Prop() onionScrollStart: ScrollCallback;
@Prop() onionScroll: ScrollCallback;
@ -48,7 +39,7 @@ export class Scroll {
/**
* @output {ScrollEvent} Emitted while scrolling.
*/
@Event() ionScroll: EventEmitter;
@Event({bubbles: false}) ionScroll: EventEmitter;
/**
* @output {ScrollEvent} Emitted when the scroll has ended.
@ -62,6 +53,7 @@ export class Scroll {
const gestureCtrl = Ionic.gesture = Ionic.gesture || new GestureController();
this.gesture = gestureCtrl.createGesture('scroll', 100, false);
this.app = this.el.closest('ion-app') as HTMLIonAppElement;
}
componentDidUnload() {
@ -69,6 +61,20 @@ export class Scroll {
this.gesture = this.detail = this.detail.event = null;
}
// Native Scroll *************************
@Listen('scroll', { passive: true })
onNativeScroll() {
if (!this.queued) {
this.queued = true;
this.dom.read(timeStamp => {
this.queued = false;
this.onScroll(timeStamp);
});
}
}
@Method()
scrollToTop(duration: number): Promise<void> {
return this.scrollToPoint(0, 0, duration);
@ -106,8 +112,8 @@ export class Scroll {
}
if (duration < 32) {
self.setTop(y);
self.setLeft(x);
el.scrollTop = y;
el.scrollLeft = x;
done();
return promise;
}
@ -139,11 +145,11 @@ export class Scroll {
const easedT = (--time) * time * time + 1;
if (fromY !== y) {
self.setTop((easedT * (y - fromY)) + fromY);
el.scrollTop = (easedT * (y - fromY)) + fromY;
}
if (fromX !== x) {
self.setLeft(Math.floor((easedT * (x - fromX)) + fromX));
el.scrollLeft = Math.floor((easedT * (x - fromX)) + fromX);
}
if (easedT < 1) {
@ -173,33 +179,23 @@ export class Scroll {
return promise;
}
// Native Scroll *************************
@Listen('scroll', { passive: true })
protected onNativeScroll() {
if (!this.queued) {
this.queued = true;
this.dom.read(timeStamp => {
this.queued = false;
this.onScroll(timeStamp);
});
}
}
private onScroll(timeStamp: number) {
const detail = this.detail;
const positions = this.positions;
const el = this.el;
if (this.app) {
this.app.setScrolling();
}
detail.timeStamp = timeStamp;
// get the current scrollTop
// ******** DOM READ ****************
detail.scrollTop = this.getTop();
detail.scrollTop = el.scrollTop;
// get the current scrollLeft
// ******** DOM READ ****************
detail.scrollLeft = this.getLeft();
detail.scrollLeft = el.scrollLeft;
if (!this.isScrolling) {
// currently not scrolling, so this is a scroll start
@ -215,9 +211,8 @@ export class Scroll {
// emit only on the first scroll event
if (this.onionScrollStart) {
this.onionScrollStart(detail);
} else {
this.ionScrollStart.emit(detail);
}
this.ionScrollStart.emit(detail);
}
// actively scrolling
@ -270,7 +265,6 @@ export class Scroll {
}
}
private onEnd(timeStamp: number) {
const detail = this.detail;
@ -279,49 +273,8 @@ export class Scroll {
// emit that the scroll has ended
if (this.onionScrollEnd) {
this.onionScrollEnd(detail);
} else {
this.ionScrollEnd.emit(detail);
}
}
/** DOM READ */
private getTop() {
if (this.jsScroll) {
return this._t;
}
return this._t = this.el.scrollTop;
}
/** DOM READ */
private getLeft() {
if (this.jsScroll) {
return 0;
}
return this._l = this.el.scrollLeft;
}
/** DOM WRITE */
private setTop(top: number) {
this._t = top;
if (this.jsScroll) {
this.el.style.transform = this.el.style.webkitTransform = `translate3d(${this._l * -1}px,${top * -1}px,0px)`;
} else {
this.el.scrollTop = top;
}
}
/** DOM WRITE */
private setLeft(left: number) {
this._l = left;
if (this.jsScroll) {
this.el.style.transform = this.el.style.webkitTransform = `translate3d(${left * -1}px,${this._t * -1}px,0px)`;
} else {
this.el.scrollLeft = left;
}
this.ionScrollEnd.emit(detail);
}
render() {

View File

@ -149,7 +149,7 @@
color: $color-base;
}
.searchbar-ios-#{$color-name} .searchbar-ios-cancel:hover:not(.disable-hover) {
.enable-hover .searchbar-ios-#{$color-name} .searchbar-ios-cancel:hover {
color: color-shade($color-base);
}

View File

@ -36,7 +36,7 @@
fill: $tabs-ios-tab-icon-color;
}
.tabbar-ios ion-tab-button:hover:not(.disable-hover),
.enable-hover .tabbar-ios ion-tab-button:hover,
.tabbar-ios .tab-selected {
color: $tabs-ios-tab-text-color-active;

View File

@ -145,7 +145,7 @@
fill: rgba($color-contrast, $tabs-md-tab-opacity);
}
.tabbar-md-#{$color-name} ion-tab-button:hover:not(.disable-hover),
.enable-hover .tabbar-md-#{$color-name} ion-tab-button:hover,
.tabbar-md-#{$color-name} ion-tab-button.tab-selected {
color: $color-contrast;

View File

@ -0,0 +1,11 @@
# ion-tap-click
<!-- Auto Generated Below -->
----------------------------------------------
*Built by [StencilJS](https://stenciljs.com/)*

View File

@ -0,0 +1 @@
@import "../../themes/ionic.globals";

View File

@ -0,0 +1,190 @@
import { Component, Element, EventListenerEnable, Listen, Prop } from '@stencil/core';
import { now, pointerCoordX, pointerCoordY } from '../../utils/helpers';
import { GestureController } from '../gesture-controller/gesture-controller';
declare const Ionic: { gesture: GestureController };
@Component({
tag: 'ion-tap-click',
styleUrl: 'tap-click.scss'
})
export class TapClick {
private app: HTMLIonAppElement;
private lastTouch = 0;
private lastActivated = 0;
private gestureCtrl: GestureController;
private activatableEle: HTMLElement;
private activeDefer: any;
private clearDefers = new WeakMap<HTMLElement, any>();
passive = true;
attachTo = 'document';
@Prop({context: 'enableListener'}) enableListener: EventListenerEnable;
@Element() el: HTMLElement;
componentDidLoad() {
this.gestureCtrl = Ionic.gesture = Ionic.gesture || new GestureController();
this.app = this.el.closest('ion-app') as HTMLIonAppElement;
}
@Listen('document:click', {passive: false, capture: true})
onBodyClick(ev: any) {
if (this.shouldCancel()) {
ev.preventDefault();
ev.stopPropagation();
}
}
// Touch Events
@Listen('document:touchstart', { passive: true })
onTouchStart(ev: TouchEvent) {
this.lastTouch = now(ev);
this.pointerDown(ev);
}
@Listen('document:touchcancel', { passive: true })
onTouchCancel(ev: TouchEvent) {
this.lastTouch = now(ev);
this.pointerUp(ev);
}
@Listen('document:touchend', { passive: true })
onTouchEnd(ev: TouchEvent) {
this.lastTouch = now(ev);
this.pointerUp(ev);
}
@Listen('document:mousedown', { passive: true })
onMouseDown(ev: MouseEvent) {
const t = now(ev);
if (this.lastTouch < t - MOUSE_WAIT) {
this.pointerDown(ev);
}
}
@Listen('document:mouseup', { passive: true })
onMouseUp(ev: TouchEvent) {
const t = now(ev);
if (this.lastTouch < t - MOUSE_WAIT) {
this.pointerUp(ev);
}
}
@Listen('body:ionScrollStart')
scrollStarted() {
clearTimeout(this.activeDefer);
if (this.activatableEle) {
this.removeActivated(false);
this.activatableEle = null;
}
}
private pointerDown(ev: any) {
if (this.activatableEle) {
return;
}
if (!this.shouldCancel()) {
this.setActivatedElement(getActivatableTarget(ev.target), ev);
}
}
private pointerUp(ev: UIEvent) {
this.setActivatedElement(null, ev);
}
private setActivatedElement(el: HTMLElement, ev: UIEvent) {
// do nothing
const activatableEle = this.activatableEle;
if (el && el === activatableEle) {
return;
}
clearTimeout(this.activeDefer);
this.activeDefer = null;
const eventX = pointerCoordX(ev);
const eventY = pointerCoordY(ev);
// unactivate selected
if (activatableEle) {
if (this.clearDefers.has(activatableEle)) {
throw new Error('internal error');
}
if (!activatableEle.classList.contains(ACTIVATED)) {
this.addActivated(activatableEle, eventX, eventY);
}
this.removeActivated(true);
}
// activate
if (el) {
const deferId = this.clearDefers.get(el);
if (deferId) {
clearTimeout(deferId);
this.clearDefers.delete(el);
}
el.classList.remove(ACTIVATED);
this.activeDefer = setTimeout(() => {
this.addActivated(el, eventX, eventY);
this.activeDefer = null;
}, ADD_ACTIVATED_DEFERS);
}
this.activatableEle = el;
}
private addActivated(el: HTMLElement, x: number, y: number) {
this.lastActivated = Date.now();
el.classList.add(ACTIVATED);
const event = new CustomEvent('ionActivated', {
bubbles: false,
detail: {x, y}
});
el.dispatchEvent(event);
}
private removeActivated(smooth: boolean) {
const activatableEle = this.activatableEle;
const time = CLEAR_STATE_DEFERS - Date.now() + this.lastActivated;
if (smooth && time > 0) {
const deferId = setTimeout(() => {
activatableEle.classList.remove(ACTIVATED);
this.clearDefers.delete(activatableEle);
}, CLEAR_STATE_DEFERS);
this.clearDefers.set(activatableEle, deferId);
} else {
activatableEle.classList.remove(ACTIVATED);
}
}
private shouldCancel(): boolean {
if (!this.app.isEnabled()) {
console.debug('click prevent: appDisabled');
return true;
}
if (this.gestureCtrl.isCaptured()) {
console.debug('click prevent: tap-click (gesture is captured)');
return true;
}
return false;
}
}
function getActivatableTarget(el: HTMLElement): any {
return el.closest('a,button,[tappable]');
}
const ACTIVATED = 'activated';
const ADD_ACTIVATED_DEFERS = 200;
const CLEAR_STATE_DEFERS = 200;
const MOUSE_WAIT = 2500;

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Button Effect - Basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
<style>
.my-block {
position: relative;
background: blue;
color: white;
width: 300px;
height: 100px;
margin: 1rem;
}
</style>
</head>
<body>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Button Effect - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding no-bounce>
<p>
<ion-button size="small">Small</ion-button>
</p>
<p>
<ion-button size="large">Large</ion-button>
</p>
<p>
<ion-button size="large" fill="outline">Large</ion-button>
</p>
<p>
<ion-button size="large" fill="clear">Large</ion-button>
</p>
<div class="my-block">
<ion-ripple-effect></ion-ripple-effect>
This is just a div + effect behind
<ion-button onclick="buttonClicked()">Nested button</ion-button>
</div>
<div class="my-block">
This is just a div + effect on top
<ion-button onclick="buttonClicked()">Nested button</ion-button>
<ion-ripple-effect></ion-ripple-effect>
</div>
<div class="my-block">
This is just a div + effect
<ion-ripple-effect></ion-ripple-effect>
</div>
</ion-content>
</ion-page>
</ion-app>
<script>
function blockClicked() {
console.log('block clicked');
return true;
}
function buttonClicked() {
console.log('button clicked');
}
</script>
</body>
</html>

View File

@ -159,15 +159,17 @@
color: $color-base;
background-color: transparent;
&:hover:not(.disable-hover) {
color: $color-base;
}
&.activated {
opacity: .4;
}
}
.enable-hover .bar-button-#{$color-name}-ios:hover,
.enable-hover .bar-button-clear-ios-#{$color-name}:hover,
.enable-hover .bar-button-ios-#{$color-name}:hover {
color: $color-base;
}
}
// iOS Toolbar Button Icon
@ -188,16 +190,16 @@
color: $toolbar-ios-button-color;
background-color: transparent;
&:hover:not(.disable-hover) {
opacity: .4;
}
&.activated {
color: color-contrast($colors-ios, $toolbar-ios-button-color);
background-color: $toolbar-ios-button-color;
}
}
.enable-hover .bar-button-outline-ios:hover {
opacity: .4;
}
@mixin ios-bar-button-outline($color-name, $color-base, $color-contrast) {
.bar-button-outline-ios-#{$color-name} {
@ -222,11 +224,6 @@
color: color-contrast($colors-ios, $toolbar-ios-button-color);
background-color: $toolbar-ios-button-color;
&:hover:not(.disable-hover) {
color: color-contrast($colors-ios, $toolbar-ios-button-color);
opacity: .4;
}
&.activated {
color: color-contrast($colors-ios, $toolbar-ios-button-color);
background-color: color-shade($toolbar-ios-button-color);
@ -234,6 +231,11 @@
}
}
.enable-hover .bar-button-solid-ios:hover {
color: color-contrast($colors-ios, $toolbar-ios-button-color);
opacity: .4;
}
@mixin ios-bar-button-solid($color-name, $color-base, $color-contrast) {
.bar-button-solid-ios-#{$color-name} {

View File

@ -167,10 +167,12 @@
.bar-button-md-#{$color-name} {
color: $color-base;
background-color: transparent;
}
&:hover:not(.disable-hover) {
color: $color-base;
}
.enable-hover .bar-button-#{$color-name}-md:hover,
.enable-hover .bar-button-clear-md-#{$color-name}:hover,
.enable-hover .bar-button-md-#{$color-name}:hover {
color: $color-base;
}
}
@ -194,10 +196,6 @@
color: $toolbar-md-button-color;
background-color: transparent;
&:hover:not(.disable-hover) {
opacity: .4;
}
&.activated {
background-color: transparent;
}
@ -207,6 +205,10 @@
}
}
.enable-hover .bar-button-outline-md:hover {
opacity: .4;
}
@mixin md-bar-button-outline($color-name, $color-base, $color-contrast) {
.bar-button-outline-md-#{$color-name} {
@ -234,16 +236,18 @@
color: color-contrast($colors-md, $toolbar-md-button-color, md);
background-color: $toolbar-md-button-color;
&:hover:not(.disable-hover) {
color: color-contrast($colors-md, $toolbar-md-button-color, md);
}
&.activated {
color: color-contrast($colors-md, $toolbar-md-button-color, md);
background-color: color-shade($toolbar-md-button-color);
}
}
.enable-hover .bar-button-solid-md:hover {
color: color-contrast($colors-md, $toolbar-md-button-color, md);
}
@mixin md-bar-button-solid($color-name, $color-base, $color-contrast) {
.bar-button-solid-md-#{$color-name} {