Skip to content

Commit

Permalink
fix(ripple-effect): follow MD spec (#16330)
Browse files Browse the repository at this point in the history
* fix(ripple-effect): follow md spec

* add box-shadow back

* add ripple effect to alert and action-sheet
  • Loading branch information
manucorporat authored Nov 15, 2018
1 parent 02a266c commit 6d59446
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 60 deletions.
2 changes: 1 addition & 1 deletion core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3541,7 +3541,7 @@ export namespace Components {
/**
* Adds the ripple effect to the parent element
*/
'addRipple': (pageX: number, pageY: number) => void;
'addRipple': (pageX: number, pageY: number) => Promise<() => void>;
}
interface IonRippleEffectAttributes extends StencilHTMLAttributes {}

Expand Down
4 changes: 0 additions & 4 deletions core/src/components/action-sheet/action-sheet.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@
overflow: hidden;
}

.action-sheet-button.activated {
background: $action-sheet-md-button-background-activated;
}

.action-sheet-icon {
@include padding(null, null, 4px, null);
@include margin($action-sheet-md-icon-margin-top, $action-sheet-md-icon-margin-end, $action-sheet-md-icon-margin-bottom, $action-sheet-md-icon-margin-start);
Expand Down
1 change: 1 addition & 0 deletions core/src/components/action-sheet/action-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
{b.icon && <ion-icon icon={b.icon} lazy={false} class="action-sheet-icon" />}
{b.text}
</span>
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
)}
</div>
Expand Down
4 changes: 0 additions & 4 deletions core/src/components/alert/alert.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,6 @@
overflow: hidden;
}

.alert-button.activated {
background-color: $alert-md-button-background-color-activated;
}

.alert-button-inner {
justify-content: $alert-md-button-group-justify-content;
}
2 changes: 1 addition & 1 deletion core/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ export class Alert implements ComponentInterface, OverlayInterface {
{i.label}
</div>
</div>
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
))}
</div>
Expand Down Expand Up @@ -429,6 +428,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
<span class="alert-button-inner">
{button.text}
</span>
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
)}
</div>
Expand Down
5 changes: 5 additions & 0 deletions core/src/components/button/button.ios.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

// iOS Solid Button
// --------------------------------------------------

:host(.button-solid) {
--background-activated: #{ion-color(primary, shade)};
}

@media (any-hover: hover) {
:host(.button-solid:hover) {
--opacity: #{$button-ios-opacity-hover};
Expand Down
1 change: 1 addition & 0 deletions core/src/components/button/button.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
// --------------------------------------------------

:host(.button-solid) {
--background-activated: var(--background);
--box-shadow: #{$button-md-box-shadow};
}

Expand Down
4 changes: 1 addition & 3 deletions core/src/components/button/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
// Default Solid Color
:host(.button-solid) {
--background: #{ion-color(primary, base)};
--background-activated: #{ion-color(primary, shade)};
--background-focused: #{ion-color(primary, shade)};
--color: #{ion-color(primary, contrast)};
--color-activated: #{ion-color(primary, contrast)};
Expand All @@ -87,8 +86,7 @@
}

// Focused/Activated Solid Button with Color
:host(.button-solid.ion-color.focused) .button-native,
:host(.button-solid.ion-color.activated) .button-native {
:host(.button-solid.ion-color.focused) .button-native {
background: #{current-color(shade)};
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/components/fab-button/fab-button.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

:host {
--background: #{$fab-md-background-color};
--background-activated: #{$fab-md-background-color-activated};
--background-activated: var(--background);
--background-focused: var(--background-activated);
--color: #{$fab-md-text-color};
--color-activated: #{$fab-md-text-color};
Expand Down Expand Up @@ -45,4 +45,4 @@

:host(.fab-button-in-list) ::slotted(ion-icon) {
font-size: $fab-md-list-button-icon-font-size;
}
}
4 changes: 1 addition & 3 deletions core/src/components/item/item.md.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@
:host {
--min-height: #{$item-md-min-height};
--background: var(--ion-item-background, transparent);
--background-activated: #{$item-md-background-activated};
--background-activated: var(--background);
--border-color: #{$item-md-border-bottom-color};
--color: #{$item-md-color};
--transition: background-color 300ms cubic-bezier(.4, 0, .2, 1);
--padding-start: #{$item-md-padding-start};
--background: #{$item-md-background};
--background-activated: #{$item-md-background-activated};
--color: #{$item-md-color};
--border-color: #{$item-md-border-bottom-color};
--inner-padding-end: #{$item-md-padding-end};
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/ripple-effect/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The ripple effect component adds the [Material Design ink ripple interaction eff

## Methods

### `addRipple(pageX: number, pageY: number) => void`
### `addRipple(pageX: number, pageY: number) => Promise<() => void>`

Adds the ripple effect to the parent element

Expand All @@ -21,7 +21,7 @@ Adds the ripple effect to the parent element

#### Returns

Type: `void`
Type: `Promise<() => void>`



Expand Down
49 changes: 41 additions & 8 deletions core/src/components/ripple-effect/ripple-effect.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
// Material Design Ripple Effect
// --------------------------------------------------

$scale-duration: 225ms;
$fade-in-duration: 75ms;
$fade-out-duration: 150ms;
$opacity-duration: $fade-in-duration + $fade-out-duration;

:host {
@include position(0, 0, 0, 0);

Expand All @@ -23,23 +28,51 @@

contain: strict;
opacity: 0;
animation-name: rippleAnimation;
animation-duration: 200ms;
animation-timing-function: ease-out;
animation:
$scale-duration rippleAnimation forwards,
$fade-in-duration fadeInAnimation forwards;

will-change: transform, opacity;
pointer-events: none;
}

.fade-out {
transform: translate(var(--translate-end)) scale(var(--final-scale, 1));
animation: $fade-out-duration fadeOutAnimation forwards;
}

@keyframes rippleAnimation {
0% {
transform: scale(.1);
from {
animation-timing-function: cubic-bezier(.4, 0, .2, 1);

opacity: .2;
transform: scale(1);
}

100% {
transform: scale(1);
to {
transform: translate(var(--translate-end)) scale(var(--final-scale, 1));
}
}

@keyframes fadeInAnimation {
from {
animation-timing-function: linear;

opacity: 0;
}

to {
opacity: 0.16;
}
}

@keyframes fadeOutAnimation {
from {
animation-timing-function: linear;

opacity: 0.16;
}

to {
opacity: 0;
}
}
80 changes: 49 additions & 31 deletions core/src/components/ripple-effect/ripple-effect.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, ComponentInterface, Element, Method, Prop, QueueApi } from '@stencil/core';

import { Config } from '../../interface';
import { rIC } from '../../utils/helpers';

@Component({
tag: 'ion-ripple-effect',
Expand All @@ -20,42 +19,61 @@ export class RippleEffect implements ComponentInterface {
* Adds the ripple effect to the parent element
*/
@Method()
addRipple(pageX: number, pageY: number) {
async addRipple(pageX: number, pageY: number) {
if (this.config.getBoolean('animated', true)) {
rIC(() => this.prepareRipple(pageX, pageY));
return this.prepareRipple(pageX, pageY);
}
return () => { return; };
}

private prepareRipple(pageX: number, pageY: number) {
let x: number;
let y: number;
let size: number;

this.queue.read(() => {
const rect = this.el.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
size = Math.min(Math.sqrt(width * width + height * height) * 2, MAX_RIPPLE_DIAMETER);
x = pageX - rect.left - (size * 0.5);
y = pageY - rect.top - (size * 0.5);
});
this.queue.write(() => {
const div = this.win.document.createElement('div');
div.classList.add('ripple-effect');
const style = div.style;
const duration = Math.max(RIPPLE_FACTOR * Math.sqrt(size), MIN_RIPPLE_DURATION);
style.top = y + 'px';
style.left = x + 'px';
style.width = style.height = size + 'px';
style.animationDuration = duration + 'ms';

const container = this.el.shadowRoot || this.el;
container.appendChild(div);
setTimeout(() => div.remove(), duration + 50);
return new Promise<() => void>(resolve => {
this.queue.read(() => {
const rect = this.el.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
const hypotenuse = Math.sqrt(width * width + height * height);
const maxRadius = hypotenuse + PADDING;
const maxDim = Math.max(height, width);
const posX = pageX - rect.left;
const posY = pageY - rect.top;

const initialSize = Math.floor(maxDim * INITIAL_ORIGIN_SCALE);
const finalScale = maxRadius / initialSize;
const x = posX - initialSize * 0.5;
const y = posY - initialSize * 0.5;
const moveX = width * 0.5 - posX;
const moveY = height * 0.5 - posY;

this.queue.write(() => {
const div = this.win.document.createElement('div');
div.classList.add('ripple-effect');
const style = div.style;
style.top = y + 'px';
style.left = x + 'px';
style.width = style.height = initialSize + 'px';
style.setProperty('--final-scale', `${finalScale}`);
style.setProperty('--translate-end', `${moveX}px, ${moveY}px`);

const container = this.el.shadowRoot || this.el;
container.appendChild(div);
setTimeout(() => {
resolve(() => {
removeRipple(div);
});
}, 225 + 100);
});
});
});
}
}

const RIPPLE_FACTOR = 35;
const MIN_RIPPLE_DURATION = 260;
const MAX_RIPPLE_DIAMETER = 550;
function removeRipple(ripple: HTMLElement) {
ripple.classList.add('fade-out');
setTimeout(() => {
ripple.remove();
}, 200);
}

const PADDING = 10;
const INITIAL_ORIGIN_SCALE = 0.5;
6 changes: 5 additions & 1 deletion core/src/utils/tap-click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export function startTapClick(doc: Document) {
let scrolling = false;

let activatableEle: HTMLElement | undefined;
let activeRipple: Promise<() => void> | undefined;
let activeDefer: any;

const clearDefers = new WeakMap<HTMLElement, any>();
Expand Down Expand Up @@ -116,11 +117,14 @@ export function startTapClick(doc: Document) {

const rippleEffect = getRippleEffect(el);
if (rippleEffect && rippleEffect.addRipple) {
rippleEffect.addRipple(x, y);
activeRipple = rippleEffect.addRipple(x, y);
}
}

function removeActivated(smooth: boolean) {
if (activeRipple !== undefined) {
activeRipple.then(remove => remove());
}
const active = activatableEle;
if (!active) {
return;
Expand Down

0 comments on commit 6d59446

Please sign in to comment.