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

How to programmatically swipe any list item to reveal the trailing actions #15

Closed
pureniti-harry opened this issue May 5, 2021 · 7 comments

Comments

@pureniti-harry
Copy link

Hi,

Thank you for making this library with many swipe options! A very useful thing for the web 💯. I have this problem integrating this library into my app because I'm not able to do this one thing which is critical for UX perspective.

Is your feature request related to a problem? Please describe.

I'm working on an app where I want to show that the list is swipeable to new users so they know they can swipe an item to perform operations. I have a tooltip with animation which should play along with the automatic swipe transition.

Describe the solution you'd like

For the first-time users, the first item in the list should automatically(programmatically) swipe when the page loads and the tooltip animation starts playing. When the user taps anywhere on the screen the item should go back to its original state, along with hiding the tooltip and stopping its animation.

Tooltip and animation are taken care of, just this part is giving me hard times.

Describe alternatives you've considered

We have a custom solution for swiping the lists and animation in place, but it's not very interactive and users are having a hard time swiping the items.

@marekrozmus
Copy link
Owner

Hi :),

Could you please describe what API would you need and how it should work exactly?
Do you need some specific duration length and so on?

So far I understand that you just want the item to behave like when user swipes item?

@pureniti-harry
Copy link
Author

Could you please describe what API would you need and how it should work exactly?

One way I was thinking to solve this is by using the drag/touch events if we can trigger them programmatically (not really sure on that, gotta give it a shot first!).

And another way I was thinking if we can have a prop to <SwipeableListItem> such as <SwipeableListItem showTrailingActions={true} /> when we set this prop set to true it would show up the trailing actions with the transition of swipe.

Do you need some specific duration length and so on?

Default transition is cool if we could just augment the swipe!

So far I understand that you just want the item to behave like when user swipes item?

Yes, basically I want users to know that a list item is swipeable because unless we don't show them, they might not know about it.

@pureniti-harry
Copy link
Author

I tried firing custom touch/mouse events on the list item element using the below functions but, it seems it's not working as expected.

/**
 * It triggers touch events. Also supports multiple touch events.
 * @param {Element} element target DOM element
 * @param {string} type type of event
 * @param {Array} touches {x, y, id} position and identifier of the event
 */
export function simulateTouchEvent(element, type, touches) {
  const touchEvents = [];

  touches.forEach((touch) => {
    touchEvents.push(
      new Touch({
        screenX: touch.x,
        screenY: touch.y,
        pageX: touch.x,
        pageY: touch.y,
        clientX: touch.x,
        clientY: touch.y,
        identifier: touch.id,
        target: element,
        force: 10,
      })
    );
  });

  element.dispatchEvent(
    new TouchEvent(type, {
      touches: touchEvents,
      view: window,
      cancelable: true,
      bubbles: true,
    })
  );
}

/**
 * It triggers mouse event.
 * @param {string} type type of event
 * @param {Element} element target DOM element
 * @param {number} x clientX of event
 * @param {number} y clientY of event
 */
export function simulateMouseEvent(type, element, x, y) {
  const evt = document.createEvent('MouseEvents');
  evt.initMouseEvent(
    type,
    true,
    true,
    window,
    1,
    x,
    y,
    x,
    y,
    false,
    false,
    false,
    false,
    0,
    element
  );
  element.dispatchEvent(evt);
}

And, in my component where I'm rendering the list,

const MySwipeableListComponent = (props) => {
  // ... other code 
 useEffect(() => {
    setTimeout(() => {
        if (showActions) {
          const el = document.querySelector('.swipeable-list-item'); // the list item root (it will get the first element from list)
          const pos = el.getBoundingClientRect();
          const center1X = Math.floor((pos.left + pos.right) / 2);
          const center1Y = Math.floor((pos.top + pos.bottom) / 2);

         setShowActions(true);
         // simulating the mouse drag on only x-axis with 100 pixels drag from right to left
         simulateMouseEvent('mousemove', el, center1X, center1Y);
         simulateMouseEvent('mouseup', el, center1X - 100, center1Y);
        
        // similarly tried with simulating touch events as well, but no luck
        simulateTouchEvent(el, 'ontouchstart', [
              { // for touch
                x: center1X,
                y: center1Y,
                id: 100,
              },
            ]);

            simulateTouchEvent(el, 'touchend', [
              {
                x: center1X - 150,
                y: center1Y,
                id: 100,
              },
            ]);
        }
    }, 500);
  }, [showActions]);

 return (
        <SwipeableList fullSwipe={false} type={ListType.IOS} threshold={threshold}>
          {items.map((item, index) => (
            <SwipeableListItem
              key={`item__${item._id}`}
              trailingActions={trailingActions(item)}
            >
              <Item
                item={item}
                onDelete={onDeleteItemHandler}
              />
            </SwipeableListItem>
          ))}
        </SwipeableList>
    );
};

@marekrozmus
Copy link
Owner

Hi, sorry to keep you waiting but I got busy week and hopefully will get some free time to check that on weekend. So stay tuned :)
BTW: wouldn't it be easier to record a GIF animation and place it on layer above the list ;)?

@marekrozmus
Copy link
Owner

Hi - I got it working with the code you've provided. Just few changes were needed.

This is method for swipe simulation:

const simulateSwipe = (el, fromPoint, to, step) => {
  if (fromPoint.x >= to) {
    simulateMouseEvent('mouseup', el, fromPoint.x, fromPoint.y);
  } else {
    setTimeout(() => {
      simulateMouseEvent('mousemove', el, fromPoint.x + step, fromPoint.y);

      simulateSwipe(el, { ...fromPoint, x: fromPoint.x + step }, to, step);
    }, 100);
  }
};

and here is your code with some changes:

const el = document.querySelector('.swipeable-list-item__content');
const pos = el.getBoundingClientRect();
const center1X = Math.floor((pos.left + pos.right) / 2);
const center1Y = Math.floor((pos.top + pos.bottom) / 2);

simulate(el, 'mousedown', { pointerX: center1X, pointerY: center1Y });

simulateSwipe(el, { x: center1X, y: center1Y }, center1X + 100, 5);

as you can see the element for events was incorrect and we need setTimeout usage between moves so that requestAnimationFrame callback is triggered.

You can change step and setTimeout delay parameter to have the animation look smoother.

Here is the result :)
Animation

Let me know if that helps and send me some GIF or images (if you can) with your results :)

@pureniti-harry
Copy link
Author

Hey, sorry for the delay. I forgot about this because we thought we'd leave this part for now and move forward with other things. I haven't yet implemented this, but I'll give this a shot in the app once we're free from the major tasks. Once done, I'll try to share the GIF if possible!

I think we can close this ticket! ✌️

Thanks a lot for the support! 😃

@marekrozmus
Copy link
Owner

@timothymiller Here is full code of example: https://github.com/marekrozmus/react-swipeable-list/tree/main/examples/src/programmatically

Unfortunately it is just proof of concept but there is problem that also other mouse events are captured during the swipe. I would need some more time to do that in proper way. If you have any ideas please let me know :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants