PolymerElements / paper-ripple

Adds a Material Design ripple effect to UI elements
https://webcomponents.org/element/PolymerElements/paper-ripple
56 stars 27 forks source link

Disable ripple effect on touch-drags #90

Open kristfal opened 7 years ago

kristfal commented 7 years ago

Description

paper-ripple currently animates on mousedown, which means that on mobile devices, the ripple effect is playing when you drag a finger over the ripple-able container. When using paper-ripple in an on-tap context, such as when adding an on-tap listener to paper-button, the ripple may fire without firing the on-tap event.

During 'regular use' a user may attempt to tap on a button, but accidentally drag her/his finger slightly. In this case, the ripple will fire, but the on-tap event will not fire. This is highly confusing for the user, as the ripple indicates that element was activated.

Native implementations of ripple effects in material design apps (Google Maps, Inbox etc.) does not play on drag. Instead, they follow the pattern of Polymer's on-tap gesture handler, and wait for a small duration to verify that the intended input was an actual tap before playing. If the user drags on the element after the initial wait, the ripple effect is cancelled.

Expected outcome

Dragging touch events should not play the ripple-effect. The implementation should follow that of Google Maps or Google Inbox. This option may be active by default or added by an element property.

Actual outcome

Dragging touch events activate the paper-ripple effect.

Live Demo

https://elements.polymer-project.org/elements/paper-ripple?view=demo:demo/index.html&active=paper-ripple

Steps to reproduce

  1. Tap and drag in a fluent motion on a paper-button
  2. The ripple will play, but the button on-tap event will not

    Browsers Affected

– [X] Mobile Safari – [X] Mobile Chrome

isaldarriaga commented 7 years ago

This is true in a scrollable container like the iron-list.

The api provide mechanisms to solve the problem though.

  1. disable the ripple by default (noink)
  2. prevent default the tap event
  3. find your link and related ripple object
  4. animate the ripple programmatically
  5. perform the action on ripple's transition end
      <a id="lnk" style="display:none"></a>
      <iron-list id="listCompanies" items="[[_getListItems(category.items)]]"
                 as="item" scroll-target="[[scrollTarget]]" selection-enabled>
        <template>
          <div on-tap="_onItemSelected">
<!-- 1. disable the ripple by default -->
            <paper-ripple recenters noink on-transitionend="_onTransitionEnd"></paper-ripple>
            <a link="[[_getItemHref(item)]]" on-tap="_onItemSelected">
              <custom-element />
            </a>
          </div>
        </template>
      </iron-list>
_getRipple: function (parent) {
        var ripple = undefined;
// not optimal but work in all browsers
        Polymer.dom(parent).children.forEach(function (child) {
          if (child.tagName.toLowerCase() === 'paper-ripple') {
            ripple = child;
            return;
          }
        });
        return ripple;
      },

      _onItemSelected: function (e) {
//2. prevent default the tap event
        e.preventDefault();
3. find your link and related ripple object
        var polymerTarget = Polymer.dom(e.target);
        var lnk = polymerTarget.node;
        var tagName = polymerTarget.node.tagName.toLowerCase();
        switch (tagName) {
          case 'custom-element':
            lnk = polymerTarget.parentNode;
            break;
          case 'div':
            var parent = undefined;
            if (polymerTarget.parentNode.host && polymerTarget.parentNode.host.tagName.toLowerCase() === 'q-image') {
              lnk = polymerTarget.parentNode.host.parentNode.parentNode;
            }
            break;
        }
        var ripple = this._getRipple(lnk.parentNode);
// 4. fire the ripple programmatically
        if (ripple) {
          ripple.downAction(e);
          this.async(function () {
            this.$.lnk.link = lnk.link;
            ripple.upAction(e);
          }, 1);
        }
      },

      _onTransitionEnd: function (e) {
//5. perform the action on ripple's transition end
        this.$.lnk.href = this.$.lnk.link;
        this.$.lnk.click();
        this.$.lnk.href = this.$.lnk.link = '';
      },

Hope this help.

LarsDenBakker commented 7 years ago

In my opinion this is quite a serious issue, the ripples look quite silly on our buttons, navigation tabs etc.

I don't like to build workaround like the above everywhere. What are the plans regarding this?

derhuebiii commented 6 years ago

+1

Any plans?