Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ripple): make ripples conform with specs #2859

Merged
merged 6 commits into from
Feb 10, 2017

Conversation

devversion
Copy link
Member

@devversion devversion commented Jan 29, 2017

This makes the ripple service conform with the specifications and other Material reference implementations.

See https://material.io/guidelines/motion/material-motion.html#material-motion-how-does-material-move

Reference from the Material specifications

Ink ripples confirm user input by immediately expanding outward from the point of touch. The card lifts to indicate an active state.

This means the following:

  • Ripples now trigger on mousedown
  • Ripples now persists as long as the element is being hold.
  • No longer adds an unnecessary background ripple.
  • Removes the ugly scale(0.00001) for ripple animations

Not only visually the ripple has been changed. The whole renderer has been rewritten and now has a very simple API, that can be easily used by developers.

Also the API has been changed to something more intuitive

// (pageX, pageY, config)
ripple.createRipple(0, 0, {
  centered: true, 
  speedFactor: 0.1
});

As seen in the example, developers are now able to specify a simple Ripple Config object

Live Demo: https://material2-dashboard.firebaseapp.com/button (temporary)

References #1434

@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Jan 29, 2017
@devversion
Copy link
Member Author

devversion commented Jan 30, 2017

@fxck created a comment which questioned the dimming of the Material 1 buttons

That's because Material 1 sets an option to dim the background (see). This isn't part of the specification as seen here and shouldn't be a big deal either.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice, overall very clean and much simpler tests

private _rippleElement: HTMLElement;

/** Element where the ripples are being added to. */
private _targetElement: HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we call this containerElement?

private _isMousedown: boolean = false;

/** Currently showing ripples that will be closed on mouseup. */
private _showingRipples: HTMLElement[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_activeRipples?

@Input('md-ripple-trigger')
get _triggerDeprecated() { return this.trigger; }
set _triggerDeprecated(value: HTMLElement|HTMLElement) { this.trigger = value; };
@Input('mdRippleTrigger') trigger: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather keep the type on this, even if it is clunky

(the HTMLElement|HTMLElement thing is a workaround for server-side prerendering)

isKeyEvent);
}
/** Creates a manual ripple at the specified position. */
createRipple(pageX: number, pageY: number, config?: RippleConfig) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is already the ripple class, we could just call this something like launch()

// Specify events which need to be registered on the trigger.
this._triggerEvents.set('mousedown', this.onMousedown.bind(this));
this._triggerEvents.set('mouseup', this.onMouseup.bind(this));
this._triggerEvents.set('mouseleave', this.onMouseLeave.bind(this));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using a Map, how about an array of tuples? Better for iteration

let triggerEvents: [string, (MouseEvent) => void][] = [
    ['mousedown', e => this.onMouseDown(e)],
    // ...
];

(generally prefer arrow functions to .bind())

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think that will be better for iteration. A map already provides a suitable iterator for those eventpairs.

I would personally like to stay with the Map for convenience and readability.

@devversion
Copy link
Member Author

@jelbourn Addressed your feedback. Thanks.

Copy link
Contributor

@mmalerba mmalerba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3 this is amazing

@@ -68,16 +68,16 @@
}
}

.md-checkbox:not(.md-checkbox-disabled) {
&.md-primary .md-checkbox-ripple .md-ripple-foreground {
md-checkbox:not(.md-checkbox-disabled) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use class rather than element selector (so it works with comparability mode mat-* elements as well)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I actually had that change only in this PR for testing purposes. I have another PR open for this. See #2857

Also I think we can only use the class here, as soon as Andrew's PR is merged.

@@ -18,8 +18,7 @@
<div md-ripple *ngIf="!_isRippleDisabled()" class="md-checkbox-ripple"
[mdRippleTrigger]="_getHostElement()"
[mdRippleCentered]="true"
[mdRippleSpeedFactor]="0.3"
mdRippleBackgroundColor="rgba(0, 0, 0, 0)"></div>
[mdRippleSpeedFactor]="0.3"></div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the spec say anything about what the speed of these ripples should be? i think the button one looks a little slower in your demo than it does in the specs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on Slack, we are going to have another PR to make all component ripples align with the specs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created #2901 for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I assign it to me?

let offsetX = pageX - containerRect.left;
let offsetY = pageY - containerRect.top;

let ripple = document.createElement('div');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use the Renderer to create this and set styles?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on Slack, we will revisit this in issue #308 and once we have feedback from Jeremy about this.

// ripple elements. This is critical because then the `scale` would not animate properly.
// Enforce a style recalculation by calling `getComputedStyle` and accessing any property.
// See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
window.getComputedStyle(ripple).getPropertyValue('opacity');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems like a good candidate for extracting into some DOM utility class, I don't think we have one yet, but maybe make it a private method with a note that we can extract it?


ripple.style.transform = 'scale(1)';

// Wait for the ripple to be faded in. Once faded in the ripple can be hided if the mouse is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/hided/hidden

@@ -86,112 +65,86 @@ describe('MdRipple', () => {
document.body.style.margin = originalBodyMargin;
});

function dispatchMouseEvent(type: string, offsetX = 0, offsetY = 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I swear this function is in like half of our test files, we should create a test utilities file sometime (not part of this PR though)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created #2902 for this

@@ -29,7 +29,7 @@
}
}

.md-radio-ripple .md-ripple-foreground {
.md-radio-ripple .md-ripple-element {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when adding new classes make them mat-* to make andrew's life easier :p

@devversion
Copy link
Member Author

@mmalerba Thanks for your feedback. Addressed the comments you added. Also glad you like it :)

@mmalerba
Copy link
Contributor

mmalerba commented Feb 2, 2017

lgtm

Copy link
Contributor

@tinayuangao tinayuangao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

const MIN_RIPPLE_FILL_TIME_SECONDS = 0.1;
const MAX_RIPPLE_FILL_TIME_SECONDS = 0.3;
export const RIPPLE_SPEED_PX_PER_SECOND = 170;
export const RIPPLE_FADE_OUT_DURATION = 600;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add doc somewhere to mention the fade out duration is fixed and is not changed with speed factor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Added it to the @Input() and also added comments for those constants.

@devversion devversion added the action: merge The PR is ready for merge by the caretaker label Feb 4, 2017
This makes the ripple service conform with the specifications and other Material reference implementations.

See https://material.io/guidelines/motion/material-motion.html#material-motion-how-does-material-move

This means the following:

 * Ripples now trigger on `mousedown`
 * Ripples now persists as long as the element is being hold.
 * No longer adds an unnecessary background ripple.
 * Removes the ugly `scale(0.00001)` for ripple animations

Not only visually the ripple has been changed. The whole renderer has been rewritten and now has a very simple API, that can be easily used by developers.

References angular#1434
@devversion
Copy link
Member Author

Just rebased the PR due to the compatibility changes.

@tinayuangao tinayuangao merged commit 6381948 into angular:master Feb 10, 2017
@devversion devversion deleted the feat/ripple-specs branch February 10, 2017 05:53
@abdel-ships-it
Copy link

Great PR! Was about to open up an issue about the current state of ripple effects.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants