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: #1435 Avoid double taps on buttons with tooltip on safari iOS #1442

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mrh1997
Copy link

@mrh1997 mrh1997 commented Sep 22, 2024

Due to an Safari Issue the first "mouseenter" event will block the "click" event. This can be worked around by using the "pointerenter" instead.

Closes #1435

📑 Description

As described here instead of
"mouseenter" the event "pointerenter" should be used to ensure correct behaviour on iOS-

Status

  • Not Completed
  • Completed

✅ Checks

  • My pull request adheres to the code style of this project
  • My code requires changes to the documentation
  • I have updated the documentation as required
  • I have checked the page with https://validator.unl.edu/
  • All the tests have passed
  • My pull request is based on the latest commit (not the npm version).

ℹ Additional Information

nothing

Summary by CodeRabbit

  • New Features
    • Enhanced popper interactions by updating event handling for mouse actions, improving responsiveness to various pointer events.
    • Introduced a customizable closeOnTouchDelay property for the popper, allowing users to define how long the popper remains open on touch devices.
    • Updated the speed dial button's rotation behavior to be directly tied to its open state, enhancing visual feedback during interactions.

Copy link

vercel bot commented Sep 22, 2024

@mrh1997 is attempting to deploy a commit to the Themesberg Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Sep 22, 2024

Walkthrough

The changes in the pull request enhance the Popper.svelte component by introducing a new property, closeOnTouchDelay, which allows customization of the delay before the popper closes on touch devices. The event handling logic is updated to differentiate between touch and non-touch events, and the mouse interaction events are modified to use pointerenter and pointerleave. Additionally, the SpeedDial.svelte component is refined by simplifying class management and adjusting the button rotation behavior based on its open state.

Changes

File Change Summary
src/lib/utils/Popper.svelte Added closeOnTouchDelay property, updated event handling logic for touch/non-touch events, and changed mouse interaction events to pointerenter/pointerleave.
src/lib/speed-dial/SpeedDial.svelte Modified class management in divClass and updated rotation class binding for buttons based on the open state.

Assessment against linked issues

Objective Addressed Explanation
iOS Buttons with hints requires two taps (#1435) The changes may improve event handling but do not directly resolve the two-tap issue.

Possibly related PRs

Poem

🐇 In the meadow where poppers play,
Events now dance in a new ballet.
Pointer whispers, hover with glee,
No more double taps, just click and see!
A hop, a skip, a joyful cheer,
Svelte's magic brings us near! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

vercel bot commented Sep 23, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
flowbite-svelte ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 7, 2024 1:45pm

@shinokada
Copy link
Collaborator

This breaks all the Popover examples and SpeedDial. Tooltip and Dropdown work as expected. In order to close the popover, you have to hover the popover and then out of the popover.

@shinokada
Copy link
Collaborator

I close the PR for now. Thank you for your contribution.

@shinokada shinokada closed this Sep 26, 2024
@mrh1997
Copy link
Author

mrh1997 commented Sep 26, 2024

Stop please reopen it. I have already created a fix but I am waiting with filing it until I tested it.

@mrh1997
Copy link
Author

mrh1997 commented Oct 4, 2024

@shinokada : Is this fix still lacking any requirements that does prevent it from being authorized?

@shinokada
Copy link
Collaborator

shinokada commented Oct 4, 2024

  • SpeedDial, Popover etc don't close by outside click on iOS.
  • Tooltip doesn't open iOS.

@mrh1997
Copy link
Author

mrh1997 commented Oct 5, 2024

I will have a look into the issue with not closing when clicking outside.


But regarding Tooltip does not open on iOS: Is it really not opening?
On my iOS (17.6.1) as well as Android the behaviour is like:

  • triggerBy="hover": opens on tap and closes immediately when untapping.
  • triggerBy="click": opens on tap and keeps opened

How do you think about keeping that behviour?
This simulates "hover" on a touch device and allows the user
to view the tooltip without running the action of the button
(by tapping; read the text; move the finger away from the button; untap)

@shinokada
Copy link
Collaborator

I checked on iPadOS 17.7.

triggerBy="hover": opens on tap and closes immediately when untapping.
triggerBy="click": opens on tap and keeps opened
How do you think about keeping that behviour?

This means developers have to change to triggerBy="click" if they are developing for iOS and it will affect the web as well. Is there any way that you can add setTimeout so that users have time to read the tooltip? Currently it closes immediately and not able to read it. If it is possible it is a good idea to add timeout: number = 3000 prop to delay the immediate closing.

@mrh1997
Copy link
Author

mrh1997 commented Oct 8, 2024

Your proposal (3sec timeout) is a great idea. I will implement it that way (if you are OK with that)!

I will not be able to spend time for this issue the next one or two weeks but I will fix it thereafter. So please don't close this pull request...

@mrh1997
Copy link
Author

mrh1997 commented Nov 4, 2024

@shinokada : I fixed the issue now including the timeout you proposed, but before pushing it I would like to get your opinion of another Idea:

The solution still suffers from the problem, that on mobile devices when tapping an element for viewing the Tooltip/Popover/... it is also clicked (firing whichever event is behind on:click). This is why on native Apps hints are implemented via a long tap (taping for 2-3 seks). Thus the User can decide to view the hint (tap 2-3 seks) or click (tap shorter) the element. I think this could make sense with flowbite, too (only when trigger="hover"!).

If you think so, too, I would give this a try...

@shinokada
Copy link
Collaborator

That may work but I'm not sure how it will affect to web users until I see it in action.

When triggering a Tooltip/Speeddial/Popover on a touch device
it will close after 3secs (or "closeOnTouchDelay" ms) when set to
trigger="hover".

Furthermore Svelte 5 will now behave identical to Svelte 4
(instead of two touches a single one is required)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
src/lib/utils/Popper.svelte (4)

20-20: LGTM! Consider enhancing the property documentation.

The new closeOnTouchDelay property is well-implemented with a sensible default value of 3000ms.

Consider adding more detailed documentation about the special -1 value that keeps tooltips open until tap outside:

-@prop export let closeOnTouchDelay: number = 3000;
+@prop export let closeOnTouchDelay: number = 3000; // Delay in ms before closing on touch devices. Set to -1 to keep open until tap outside.

Also applies to: 33-33, 246-246


66-68: LGTM! Consider making the touch show delay configurable.

The 300ms delay for touch events is a good solution to prevent accidental tooltip triggers while maintaining immediate response for mouse events.

Consider making the touch show delay configurable similar to closeOnTouchDelay:

+  export let showOnTouchDelay: number = 300;
   setTimeout(() => {
     open = ev.type === 'click' ? !open : true;
-  }, (ev as PointerEvent).pointerType === "touch" ? 300 : 0)
+  }, (ev as PointerEvent).pointerType === "touch" ? showOnTouchDelay : 0)

76-91: LGTM! Consider improving type safety.

The hide handler implementation properly manages different interaction modes and respects the closeOnTouchDelay setting.

Consider using type assertion for the timer to avoid the unknown cast:

-      timer = setTimeout(() => {
+      timer = window.setTimeout(() => {
         if ((ev.type === 'mouseleave' || ev.type === 'pointerleave') &&
             (isTouch || !elements.some(hasHover))) {
           open = false;
         }
-      }, closeDelay) as unknown as number;
+      }, closeDelay);

172-172: LGTM! Consider optimizing the click outside handler.

The click outside handler is a necessary addition to fix the iOS Safari issue where clicking outside doesn't close the popper.

Consider adding a passive event listener for better scrolling performance:

-    document.addEventListener('click', closeOnClickOutside);
+    document.addEventListener('click', closeOnClickOutside, { passive: true });

     return () => {
-      document.removeEventListener('click', closeOnClickOutside);
+      document.removeEventListener('click', closeOnClickOutside, { passive: true });

Also applies to: 192-200

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8146794 and 0d7447e.

📒 Files selected for processing (2)
  • src/lib/speed-dial/SpeedDial.svelte (3 hunks)
  • src/lib/utils/Popper.svelte (9 hunks)
🔇 Additional comments (4)
src/lib/speed-dial/SpeedDial.svelte (4)

62-62: Improved rotation behavior for touch devices.

Good change! Binding rotation directly to the open state instead of hover improves touch device interaction and helps fix the iOS double-tap issue. The transition class ensures smooth animation.


71-71: Consistent implementation with GradientButton.

Good! The rotation behavior is consistently implemented across both regular and gradient buttons, ensuring uniform interaction patterns.


Line range hint 49-71: Consider additional touch device testing.

The changes look good and align well with fixing the iOS double-tap issue. However, given the concerns raised in PR comments about Popover examples, please ensure comprehensive testing on:

  1. Different iOS devices and versions
  2. Various touch interaction scenarios
  3. Integration with Popover components

Consider adding automated tests for touch interactions to prevent regression:

// Example test structure for future implementation
it('should handle touch interactions correctly', async () => {
  // Test single tap opens the speed dial
  // Test rotation animation triggers with open state
  // Test child button interactions
});

49-49: Verify removal of 'group' class impact.

The removal of the hardcoded 'group' class might affect child elements that relied on group-* utility classes for styling. Please ensure this change doesn't unintentionally break any group-based hover or interaction styles.

✅ Verification successful

Removal of 'group' class is safe

The removal of the hardcoded 'group' class from SpeedDial.svelte is safe. While group-* classes are used in other components, the SpeedDial component and its direct children don't rely on group-based styling. The component uses direct class assignments for styling its button and icon elements, with transitions handled through the rotate-45 class binding.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any group-* classes in child components or related files
rg -l 'group-[a-zA-Z0-9:-]+' --type svelte

Length of output: 75


Script:

#!/bin/bash
# Search for any group-* classes in all files, without file type restriction
rg -l 'group-[a-zA-Z0-9:-]+' 

# Also check for potential group-related Tailwind classes in the SpeedDial component
rg 'class=' src/lib/speed-dial/SpeedDial.svelte -A 2 -B 2

Length of output: 1817

Comment on lines +144 to +145
['pointerenter', showHandler, hoverable],
['pointerleave', hideHandler, hoverable]
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Found inconsistency in mouse/pointer event handling

The verification revealed that while Popper.svelte has been updated to use pointer events in some places, it still contains mixed usage of mouse events in the Frame component at line 184:

on:mouseenter={optional(activeContent && hoverable, showHandler)} on:mouseleave={optional(activeContent && hoverable, hideHandler)}

This should be updated to use pointer events for consistency with the other changes:

  • src/lib/utils/Frame.svelte: Update mouseenter/mouseleave to pointerenter/pointerleave
🔗 Analysis chain

LGTM! The switch to pointer events should fix the iOS Safari issue.

Using pointer events instead of mouse events is the correct approach to handle both touch and mouse interactions consistently.

Let's verify that all mouse events have been replaced with pointer events:

Also applies to: 166-166, 184-184

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining mouse event listeners that might need updating

# Test: Search for mouseenter/mouseleave events that might have been missed
echo "Checking for remaining mouse events..."
rg -i 'mouse(enter|leave)' --type svelte

Length of output: 160


Script:

#!/bin/bash
# Let's try a more general search without file type restriction
echo "Checking for remaining mouse events in all files..."
rg -i 'mouse(enter|leave)'

# Also search for any event listeners to get a comprehensive view
echo -e "\nChecking all event listeners in the Popper component..."
rg -A 2 "addEventListener|removeEventListener" src/lib/utils/Popper.svelte

Length of output: 15736

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

Successfully merging this pull request may close these issues.

iOS Buttons with hints requires two taps
2 participants