Skip to content

Commit

Permalink
feat: Material You Ripple MVP
Browse files Browse the repository at this point in the history
This CL proposes a minimum viable interation towards the Material You Ripple for Web. It changes the existing Material Ripple in-place, adding a soft edge to the wave effect while avoiding major changes to host components.

PiperOrigin-RevId: 384550800
  • Loading branch information
material-web-copybara authored and copybara-github committed Aug 9, 2021
1 parent e8fd76b commit 2330fd5
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 10 deletions.
17 changes: 17 additions & 0 deletions packages/mdc-ripple/_ripple-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ $light-theme: (
@include states-press-opacity(map.get($theme, pressed-state-layer-opacity));
}

@mixin ripple-mask($margin, $min-ratio) {
$radial-gradient: radial-gradient(
closest-side,
#fff max(calc(100% - #{$margin}), #{$min-ratio}),
#fff0 100%
);

-webkit-mask-image: $radial-gradient;
mask-image: $radial-gradient;
}

@mixin states-base-color(
$color,
$query: feature-targeting.all(),
Expand All @@ -125,6 +136,12 @@ $light-theme: (
);
}

#{$ripple-target}::after {
@include feature-targeting.targets($feat-color) {
@include ripple-mask(70px, 65%);
}
}

#{$ripple-target}::before,
#{$ripple-target}::after {
@include feature-targeting.targets($feat-color) {
Expand Down
28 changes: 26 additions & 2 deletions packages/mdc-ripple/_ripple.scss
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
--mdc-ripple-left: 0;
--mdc-ripple-top: 0;
--mdc-ripple-fg-scale: 1;
--mdc-ripple-fg-edge-scale: 1;
--mdc-ripple-fg-translate-end: 0;
--mdc-ripple-fg-translate-start: 0;

Expand Down Expand Up @@ -189,6 +190,18 @@
left: var(--mdc-ripple-left, 0);
}
}

&.mdc-ripple-upgraded--foreground-activation {
#{$ripple-target}::after {
@include feature-targeting.targets($feat-animation) {
animation: mdc-ripple-fg-radius-in ripple-theme.$translate-duration
forwards,
mdc-ripple-fg-opacity-in ripple-theme.$fade-in-duration forwards,
mdc-unbounded-ripple-fg-mask-in ripple-theme.$translate-duration
forwards;
}
}
}
}

&.mdc-ripple-upgraded--foreground-activation {
Expand All @@ -210,7 +223,7 @@
@include feature-targeting.targets($feat-structure) {
// Retain transform from mdc-ripple-fg-radius-in activation
transform: translate(var(--mdc-ripple-fg-translate-end, 0))
scale(var(--mdc-ripple-fg-scale, 1));
scale(var(--mdc-ripple-fg-edge-scale, 1));
}
}
}
Expand Down Expand Up @@ -301,6 +314,17 @@
}

@mixin keyframes_ {
$ripple-mask-keyframes: 0% 70px 65%, 70% 70px 65%, 75% 55px 75%, 80% 40px 85%,
85% 25px 90%, 90% 10px 95%, 100% 0px 100%;

@keyframes mdc-unbounded-ripple-fg-mask-in {
@each $frame, $margin, $min-ratio in $ripple-mask-keyframes {
#{$frame} {
@include ripple-theme.ripple-mask($margin, $min-ratio);
}
}
}

@keyframes mdc-ripple-fg-radius-in {
from {
animation-timing-function: variables2.$standard-curve-timing-function;
Expand All @@ -313,7 +337,7 @@

to {
transform: translate(var(--mdc-ripple-fg-translate-end, 0))
scale(var(--mdc-ripple-fg-scale, 1));
scale(var(--mdc-ripple-fg-edge-scale, 1));
}
}

Expand Down
13 changes: 10 additions & 3 deletions packages/mdc-ripple/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const cssClasses = {

export const strings = {
VAR_FG_SCALE: '--mdc-ripple-fg-scale',
VAR_FG_EDGE_SCALE: '--mdc-ripple-fg-edge-scale',
VAR_FG_SIZE: '--mdc-ripple-fg-size',
VAR_FG_TRANSLATE_END: '--mdc-ripple-fg-translate-end',
VAR_FG_TRANSLATE_START: '--mdc-ripple-fg-translate-start',
Expand All @@ -42,9 +43,15 @@ export const strings = {
};

export const numbers = {
DEACTIVATION_TIMEOUT_MS: 225, // Corresponds to $mdc-ripple-translate-duration (i.e. activation animation duration)
FG_DEACTIVATION_MS: 150, // Corresponds to $mdc-ripple-fade-out-duration (i.e. deactivation animation duration)
DEACTIVATION_TIMEOUT_MS:
225, // Corresponds to $mdc-ripple-translate-duration (i.e. activation
// animation duration)
FG_DEACTIVATION_MS: 150, // Corresponds to $mdc-ripple-fade-out-duration
// (i.e. deactivation animation duration)
INITIAL_ORIGIN_SCALE: 0.6,
PADDING: 10,
TAP_DELAY_MS: 300, // Delay between touch and simulated mouse events on touch devices
TAP_DELAY_MS:
300, // Delay between touch and simulated mouse events on touch devices
SOFT_EDGE_MINIMUM_SIZE: 70,
SOFT_EDGE_CONTAINER_RATIO: 0.35
};
22 changes: 18 additions & 4 deletions packages/mdc-ripple/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export class MDCRippleFoundation extends MDCFoundation<MDCRippleAdapter> {
private activationTimer = 0;
private fgDeactivationRemovalTimer = 0;
private fgScale = '0';
private fgEdgeScale = '0';
private frame = {width: 0, height: 0};
private initialSize = 0;
private layoutFrame = 0;
Expand Down Expand Up @@ -516,6 +517,11 @@ export class MDCRippleFoundation extends MDCFoundation<MDCRippleAdapter> {
private layoutInternal() {
this.frame = this.adapter.computeBoundingRect();
const maxDim = Math.max(this.frame.height, this.frame.width);
const isUnbounded = this.adapter.isUnbounded();

const softEdgeSize = Math.max(
numbers.SOFT_EDGE_CONTAINER_RATIO * maxDim,
numbers.SOFT_EDGE_MINIMUM_SIZE);

// Surface diameter is treated differently for unbounded vs. bounded ripples.
// Unbounded ripple diameter is calculated smaller since the surface is expected to already be padded appropriately
Expand All @@ -526,31 +532,39 @@ export class MDCRippleFoundation extends MDCFoundation<MDCRippleAdapter> {
const getBoundedRadius = () => {
const hypotenuse = Math.sqrt(
Math.pow(this.frame.width, 2) + Math.pow(this.frame.height, 2));
return hypotenuse + MDCRippleFoundation.numbers.PADDING;
return hypotenuse + MDCRippleFoundation.numbers.PADDING + softEdgeSize;
};

this.maxRadius = this.adapter.isUnbounded() ? maxDim : getBoundedRadius();
this.maxRadius = isUnbounded ? maxDim : getBoundedRadius();

// Ripple is sized as a fraction of the largest dimension of the surface, then scales up using a CSS scale transform
const initialSize = Math.floor(maxDim * MDCRippleFoundation.numbers.INITIAL_ORIGIN_SCALE);
// Unbounded ripple size should always be even number to equally center align.
if (this.adapter.isUnbounded() && initialSize % 2 !== 0) {
if (isUnbounded && initialSize % 2 !== 0) {
this.initialSize = initialSize - 1;
} else {
this.initialSize = initialSize;
}
this.fgScale = `${this.maxRadius / this.initialSize}`;
this.fgEdgeScale = isUnbounded ?
this.fgScale :
`${(this.maxRadius + softEdgeSize) / this.initialSize}`;

this.updateLayoutCssVars();
}

private updateLayoutCssVars() {
const {
VAR_FG_SIZE, VAR_LEFT, VAR_TOP, VAR_FG_SCALE,
VAR_FG_SIZE,
VAR_LEFT,
VAR_TOP,
VAR_FG_SCALE,
VAR_FG_EDGE_SCALE,
} = MDCRippleFoundation.strings;

this.adapter.updateCssVariable(VAR_FG_SIZE, `${this.initialSize}px`);
this.adapter.updateCssVariable(VAR_FG_SCALE, this.fgScale);
this.adapter.updateCssVariable(VAR_FG_EDGE_SCALE, this.fgEdgeScale);

if (this.adapter.isUnbounded()) {
this.unboundedCoords = {
Expand Down
6 changes: 5 additions & 1 deletion packages/mdc-ripple/test/foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,14 @@ describe('MDCRippleFoundation', () => {
jasmine.clock().tick(1);

const maxSize = Math.max(width, height);
const softEdgeSize = Math.max(
numbers.SOFT_EDGE_CONTAINER_RATIO * maxSize,
numbers.SOFT_EDGE_MINIMUM_SIZE);

const initialSize = maxSize * numbers.INITIAL_ORIGIN_SCALE;
const surfaceDiameter =
Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
const maxRadius = surfaceDiameter + numbers.PADDING;
const maxRadius = surfaceDiameter + numbers.PADDING + softEdgeSize;
const fgScale = `${maxRadius / initialSize}`;

expect(adapter.updateCssVariable)
Expand Down

0 comments on commit 2330fd5

Please sign in to comment.