App: [$8000] Mac / Safari - Copy to clipboard Tooltip doesn't show copied on clicking the clipboard icon.
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Action Performed:
- Go to any chat
- Click on the participant title to open the details view
- Click on the Copy to clipboard icon 📋 in the email.
- Notice that the tooltip is shown for
Copy to clipboard
but notCopied
after the text is copied. (Videos to compare Chrome and Safari are attached)
Expected Result:
Copied
tooltip should be shown
Actual Result:
Copied
tooltip after the text is copied doesn’t show up
Workaround:
unknown
Platform:
Where is this issue occurring?
- Web - Mac / Safari
Version Number: 1.2.33-2 Reproducible in staging?: Y Reproducible in production?: Y Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos:
Expensify/Expensify Issue URL: Issue reported by: @mananjadhav Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1669714466881009
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~014886ff5b8f1db983
- Upwork Job ID: 1598039428548734976
- Last Price Increase: 2022-12-29
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 385 (350 by maintainers)
Thanks @s77rt. With the simplified proposal and both of @mollfpr’s concerns addressed, I think we’re in a good spot with your latest proposal, so let’s go with that!
@getusha that’s an interesting found.
IMO that’s a different issue, in the accepted proposal we don’t change any tooltip style related but yeah that appears because we enable the tooltip on focus.
cc @francoisl
@s77rt I raised the same earlier here but they are not considering keyboard navigation issues as of now.
Yes, there’s a possibility where the regression arises as you mention. It’s okay, to correct each other but let’s keep the conversation civil.
I also have the same thought at first. To me having
successText
on theHoverable
component doesn’t make sense and I think your proposal has the same meaning as Pujan’s proposal where it’s easier to understand.Thanks, @jatinsonijs for the summary and the example! I’ll read through your observation.
@s77rt paid $12000 @mananjadhav paid $250 anything missing!??!!?
We need to fill this out too. @mollfpr can you tackle the first three? @kevinksullivan, can you do the last one?
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
@jatinsonijs @s77rt Okay I confirm that
onModalWillShow={DomUtils.blurActiveElement}
is causing a problem regression here.Yes, I believe @francoisl can create the issue and add the
DeployBlockerCash
to the issue and the payment will be done there.@s77rt I am seeing it’s working nicely with the mouse moments 🎉 . For 2 times focus on the elements I agree with @getusha which doesn’t give a good experience. I know accessibility isn’t a concern right now but I believe we should not degrade in that direction with the current behavior.
Applied in Upwork. PR is ready.
Proposal 1 (Updated)
Details
This is my initial proposal which is also global and is based on the approach that we should not hide the tooltip in the first place, but this has one major drawback which is in Safari tooltips won’t hide unless you move the mouse. Just submitting in case we decided to ignore that behaviour on Safari.
Reviewing now…
Let’s hold on further comments until we’re able to get feedback on the existing proposals from @mananjadhav. Can that happen today?
@s77rt i am not comfortable you making this kind assumptions, it is not great to disregard and disrespect your peers opinion, As i worked on the previous issue (related to this), i just didn’t like the approach and was sharing my concern. I was also trying to see the best solution without having a proposal. Please let’s respect each others opinion and idea let’s not argue. Also please if you have proved regressions related to my proposal i would be happy to improve also take the teams opinion and try to improve.
Also for the statement let’s fix the issue globally, i don’t know what that means but if it is related to my proposal, it is not “impossible” or difficult as you tried to express that we can add
successText
on the tooltip everywhere and it’s good practice IMO. i will add it for every place and update my proposal. Please let’s not argue again, Thanks.This PR was reverted here as it was a temporary solution for this issue. cc @mollfpr @francoisl
Addressed https://github.com/Expensify/App/issues/14121#issuecomment-1396372989 Thanks for the ping @jatinsonijs
Compensating @mananjadhav 25% of the job price for their C+ work before they went OOO. This issue has close to 400 comments 😮 and there were multiple proposals that Manan reviewed.
I’ve added details to our Pricing Precedent - Contributor pay - edge cases - partial pay doc.
@mananjadhav can you address in the
#contributor-plus
Slack channel? Please provide reasoning and details, if we issue compensation, the goal would be to try to processize or document this edge case so we can reference again in the future. Also… saw344 hidden items
above 😨@mollfpr can you help @kevinksullivan and I figured out how much is owed to whom? I believe it’s
I compensated @mollfpr $8000 total - $8000 job minus half for the regression (per C+ policy) = $4000. Plus 50% for timeliness bonus = $4000
CONTRIBUTING.md has been updated to reflect the below so, going forward, no timeliness bonuses will be issued if there are regressions.
Rehired with a new price @mollfpr . Thanks for correcting me!
@kevinksullivan I think my payment is half of the bounty since it has a regression (posted https://github.com/Expensify/App/issues/14121 and reported by @jatinsonijs https://github.com/Expensify/App/issues/13146#issuecomment-1374794996). Can you change the contract? Sorry for the inconvenience.
Sorry had linked it incorrectly @mollfpr , but I found you on upwork. You can just accept the offer 👍 .
Ok, thanks. I wasn’t aware that @getusha already raised…
@s77rt You’re right. So please update the description and add videos for the solved issue.
@getusha You are doing something wrong, double check from your side
@jatinsonijs Technically you found a regression, so I think you are eligible for the $250 compensation. Let @francoisl confirm on this
@jatinsonijs thank you
@getusha AvatarCropModal using Modal so happening in this case.
There is regression after merged this branch, I have reported this issue in slack @s77rt plz confirm https://expensify.slack.com/archives/C01GTK53T8Q/p1673116732450659?thread_ts=1672933287.271659&cid=C01GTK53T8Q
In image crop Drag, zoom, rotate your image… text is not selectable. cc @mollfpr
@mollfpr
absolute
withtrue
. Even if we don’t, that won’t be a major problem but it’s better if we do. I just wanted to be clear on this point.Yes, we don’t need
resetsOnClickOutside
in the tooltip. This prop has been removed. We are only “reverting” https://github.com/Expensify/App/pull/12572 (and properly fixing https://github.com/Expensify/App/issues/12025). There would be no moreresetsOnClickOutside
prop so reverting https://github.com/Expensify/App/pull/12677 is pointless.~@mollfpr reproducible in production~
@getusha Not much difference in your proposal, and I don’t think having a hundred listeners create from a tooltip is a good idea. The callback will call
hideTooltip
on every callback listener.@francoisl If we want to go with the controlled
resetsOnClickOutside
on the tooltip, I will pick @Pujan92 proposal’s in the first place.But in this way, we just patch the https://github.com/Expensify/App/issues/12025 regression not try to fix the root cause.
@s77rt thanks for the updated proposal, I had a few questions though:
Are these changes necessary? I know you mentioned the intention is to avoid wrapping elements unnecessarily before, but… in the end, do we need to make these changes at all here?
Hoverable
, you edited theonMouseEnter
andonMouseLeave
functions with this:similarly, why is that change required? Can you point to an example where it’s required please?
BaseModal
, this is new since your previous proposal, and I’m not seeing why it’s needed either:Feel free to explain your proposal in plain English first (without code) if that’s helpful - the idea is to make sure we all understand and agree on why any given change is required, and why we’re making it that way. Thanks!
@francoisl can you take a look at my proposal?
IMO
resetsOnClickOutside
isn’t avoidable, we have seen that on many instances. i think i have addressed the concern of toggledTooltip
not being dismissed while navigating.Thanks, @getusha! I also will review your proposal later.
So far I like the idea of having focus/blur on the tooltip. I’ll review more after I test it again.
@francoisl
Yes, sorry I copy pasted and forgot to change the function name. I have updated my proposal
Okay, so here I need to explain, there are 2 cases where Tooltips are used with buttons (or Tooltip + Navigation)
On case 1, if we click on
<Pressable />
and it gets blurred, the blur event will bubble up to<Tooltip />
and we hide the tooltip, all good here. However on case 2, if we click on<Tooltip />
we can’t actually blur it since it’s not focus-able and even if we blur the<Pressable />
the blur event will never reach the tooltip (events never reach the children of the target). Making the tooltip focus able solves the issue since we can blur it now. There is also case 3 which I didn’t mention, which is<Pressable with Tooltip></Pressable>
i.e. apply the tooltip functionality but without wrapping the element (absolute
set totrue
)Taking mui-ui as a reference, case 3 is the default.
You may wonder, can’t we switch all our Case 2 scenarios into Case 1 (or Case 3). No we can’t, some hierarchies are just too complex to make such a change, besides Tooltip is valid to be used in either way, after all Tooltip can and are used on non-buttons (texts, etc.).
Not really, the use of that workaround is not really related to
<Freeze />
but to Safari in general. Take this example After you click the Pin/Unpin button, a modal will show up and cover it. on Chrome themouseleave
event will fire so the tooltip will hide. But on Safari, no event is fired (as explained the reason before), so we fire the blur event instead (since both are used to hide the tooltip). Now you may ask why we don’t fire themouseleave
since this is the missing event and not the blur event, well this part may be related to<Freeze />
since themouseleave
event is handled by<Hoverable />
and we hide the tooltip asynchronously which may get blocked by freeze taking effect while the blur event is handled by<Tooltip />
and we hide the tooltip synchronously (freeze wont take effect until we are done with hiding the tooltip). Maybe we can firemouseleave
event afterall, I just went with the more clearer way. As for the performance, it’s a cheap one call.@jatinsonijs Thanks for testing. I will explain the behaviours:
@getusha The
open
prop of<Tooltip />
is used for whether the tooltip should be open(visible) or not (controlled tooltip) and not for whether we should hide the tooltip on mouse down or not.@mollfpr Yes,
resetsOnClickOutside
property in theHoverable
won’t be required as it will be the default and must thing to do and doesn’t require any dynamic value. So we can replace it with thedismissOnClick
and pass it within theTooltip
component.Updated Proposal
Additional Info
onBlur
andonClick
events, won’tonBlur
be enough?onBlur
would be enough, but we have many elements that does not get focused (probably because they are not buttons) thus they do not emitonBlur
event but still do navigation. WithoutonClick
we would have to rely ononMouseLeave
event which may not fire unless you move the mouse especially on Safari (demo).Proposal 4
Details
In this proposal, we only hide the tooltip on blur or on click.
The events bubbles per default, so the
onClick
will only occur if we don’t stop the propagation. And we do stop the propagation if<Pressable />
is used as in the case with the context menu tooltips (so the text changes smoothly). And if we do navigation (or anything else) we haveonBlur
that takes effect to prevent the tooltips from getting stuck or being active while out of view in general. Edit: Read https://github.com/Expensify/App/issues/13146#issuecomment-1368377652 for more infoHowever, our friend Safari is not very pleased, while it works okay there is one edge case that I found: If you use Safari on a minimal window view, open a chat and click the back button, the tooltip of that back button will stay visible until you click anywhere, for some reasons the blur events does not fire immediately, again on Safari that may be the spec. But it works fine on other places such the FAB, the emoji button, etc. Even though the number of users who may be using Safari in minimal view is very slim IMO, we can still fix this or at least make it better, by applying this change in : https://github.com/Expensify/App/blob/main/src/components/Hoverable/index.js#L53 Edit: After applying the change, the tooltip will hide after animation (on drawer fully opened). Edit2: That change is outdated, check the below comment (https://github.com/Expensify/App/issues/13146#issuecomment-1368257894)
https://user-images.githubusercontent.com/16493223/210133546-f8679c6c-5abc-4288-abf1-8050bb87cd11.mp4
Just updated it you can ignore the first one.
@getusha Your solution is not global it is a workaround. And it’s the same as @Pujan92 I have said that enough time.
Wrong. The tooltip will only be dismissed on mouse move if you do modal navigation. If you do drawer navigation where
<Freeze />
kicks in, the tooltip will become stuck.Ref: https://github.com/Expensify/App/issues/13146#issuecomment-1366761645 and https://github.com/Expensify/App/issues/13146#issuecomment-1366767105
I think it’s important to take in consideration future use cases, maybe there is none now, but later we can have a complex design, if we can find a solution that works even in the worst cases then we should be safe.
Ref: https://github.com/Expensify/App/issues/13146#issuecomment-1363280002
I’m not saying Navigation && Change tooltip text, this does not make sense because we won’t see the new text. I’m saying Navigation || Change tooltip text, where a button may do navigation or change the tooltip text based on some condition.
Ref: https://github.com/Expensify/App/issues/13146#issuecomment-1364537611
I think we are looking for a global solution (and not a workaround) with no regressions.
Ref: https://github.com/Expensify/App/issues/13146#issuecomment-1363235534
I think my latest proposal (proposal 3) is the best so far, and this is based on facts, not just because it’s my proposal. Correct me if I’m wrong.
My proposal is:
My proposal also relies on hiding the tooltip then showing it again, and we are discussing if we should hide the tooltip in the first place on the slack thread.
So far, I say we should hide the tooltip on mouse down otherwise we will have those issues:
<Freeze />
reopening this issue https://github.com/Expensify/App/issues/12025That was a recap from my point of view.
Yes @mollfpr first we have to clear the requirement so that we can test properly all the cases before submit proposal. Like some latest proposal have regression on safari. Tooltip will not hide until mouse move with toggled tooltip + navigation. Is it acceptable or not. I think first we should find out the all point which must need to consider.
@mollfpr Hi, just stumbled upon it. IMO, if there is no spec yet, it’s good to communicate with the design team to determine how many scenarios and corresponding expected behaviors. Please ignore my words if I’m wrong. 😂
@Pujan92 Found an issue with your proposal. The hovered state is not reset after open closing a modal.
https://user-images.githubusercontent.com/25520267/210084099-fc41beeb-f3e0-4a4d-8967-74234f0250d9.mov
@Pujan92 Yup, review it now!
Will review both proposals tonight!
wow @s77rt
Yes, i explained that in my comment you might seen that, which was if the tooltip updates and the user doesn’t have the chance to see it due to navigation / opened modal does the successText have any value? does this make sense to you? And thank you very much for the feedbacks.
@JmillsExpensify I will start reviewing ASAP, thanks!
@getusha Your proposal causes a regression by not hiding the tooltip if the tooltip button opens a modal because your code won’t reach this part. I’m not a C+ but your code does not make sense, there is a condition to check the hover state if it’s true, why you are setting the state to true even if it’s already true, you can just do
if (this.props.resetsOnClickOutside && !this.props.successText) {
and this can be simplified to only useresetsOnClickOutside
which gets us back to @Pujan92 proposal.TLDR; Excluding the regression, they are the same.
Yes right its getting stuck on toggled tooltip + navigation + Freeze
Actually @getusha solution is the same as @Pujan92 here https://github.com/Expensify/App/issues/13146#issuecomment-1332161311
I am travelling for a few days and I can only check the updated conversations by day after tomorrow. Thanks for the patience and the active convseration folks.
yeah mousedown and mouseup are also event listener, in my proposal I have added condition on navigation event listen when we have toggled tooltip only then it should listen for state change otherwise not. so for normal tooltip it will work same as working now.
@s77rt may be I have used wrong name, I mean PR checklist something related to this like if you have added toggled tooltip in your work must check in safari and chrome etc… I saw for Input there is issue occur with emoji due to line height so they have added this in in their test list.
Hoverable component is low level component so we shouldn’t do much work on it. It may affect performance of app.
@jatinsonijs I’m still looking into this. We can differently fix this using event listeners, just looking if we can get it even better with less code being changed.
@jatinsonijs I see the problem Thanks! Shouldn’t be hard to fix. I hope
@getusha https://github.com/Expensify/App/issues/13146#issuecomment-1364528668 I have already explained, it’s just an example to catch future regressions
Here is a more imaginable scenario: A button tooltip that has successText but it will only show that successText in case a condition is met, otherwise redirection… Or the other way around A button tooltip that has errorText but it will only show that errorText in case a condition is not met, otherwise redirection… (a reasonable scenario to be found in a back button)
Makes sense now?
@s77rt your solution will not work with safari bcz safari do not change hover state also until mouse move I have already tested it. So with toggled tooltip + navigation it will not work
@getusha Navigation was just an example, the issue will happen if
Freeze
is triggered in any other ways. I like your proposal being simple but you are basically reverting the PR mentioned above (without providing an alt solution). I think that your proposal will likely cause future regressions. Besides it’s not global (and it’s impossible to make it global), we will have to passsuccessText={this.props.successText}
to everyTooltip
that may change it’s text.I have been working on another proposal (following another approach) that should work exactly as expected and hopefully it’s bullet-proof. Posting in few mins…
Global plus button, composer plus button, emoji picker etc…
Thanks for the comments team.
@jatinsonijs You’re right that we have toggled Tooltip and hence here I am looking for a solution that works for both the cases (toggled tooltip + navigation). I don’t want to fix this as a workaround or one off and then open another issue in the future for a similar case. I hope it makes sense. Let’s try to solve the root cause.
@s77rt Of all the proposals I was almost okay with your proposal. But I have my concerns related to race condition and also updating the modal styles (sorry I just saw I didn’t mention in the previous summary).
https://github.com/Expensify/App/blob/70d87b0e6662c9fc06e85c0df35e3766fa4e1d04/src/components/Hoverable/index.js#L63-L67
If you read the comment, Modal is just an example. Are we sure we’re not breaking anything at all in any scenario?
I’ll also let @francoisl review the proposal.
Thanks for the patience here team.
Here’s the summary of all the proposals that have come so far.
Passing
resetsOnClickOutside=false
to specific tooltips or removing it completely. While this works, it is more of a workaround. As you can see this is reproducible to more than one places and I don’t think disabling this is the right way to handle this.Replacing with
click
event Definitely not the way to go. It breaks things and I don’t see howclick
event will help for the hover components.Adding
setTimeout
Let’s avoid workaround solutions for this one.Proposals related to adding
text
or border/edges Don’t work and address the issue mentionedkeydown
event Again not sure how it helps for hover.Removing
resetsOnClickOutside
and removingprops
hover callbacks outside of the state callback, would lead to race conditions. I tested this and along with the other aspects of removing the code, moving to theright
instead oftransform
, it didn’t work for me. I could’ve missed something, I couldn’t get enough evidence that Freeze stops the callbacks, and as I mentioned, let’s not add race conditions by calling props before the state is updated.@francoisl What are your thoughts?
@kavimuru it’s reproducible in Pin/unpin chat too . It’s the same issue
Yes @mananjadhav right creating problem on safari even when cursor is on icon and on chrome (edges).
Proposal
I think resetsOnClickOutside not correct name for tooltip bcz its not clear to code reader why tooltip should be reset. If we pass false in it why it should not reset on outside click but actually its works different in code.
We can use new props dismissOnClick or dissmissOnInsideClick. And we can also update prop name on Hoverable also resetOnClick or resetOnInsideClick it’s using only for Tooltip.
Reason why it’s behaving different on chrome and safari is still not clear. Even on Safari it’s not working with key prop.
hi @francoisl I am going to do that today.
@getusha Yes indeed, I have noticed that, I had an idea to solve this already. Will get back to this soon
There is no need of
resetHoverStateOnOutsideClick
This must be removed, it’s only a workaround. The real problem is on the fact that the element is suspended and callback setState does not get called.Proposal
As
resetsOnClickOutside
added to solve this issue, we can pass valuefalse
for our use case(for copy actions)https://github.com/Expensify/App/blob/1527fdcf443713bb058e6e76504006d74f6b1aa8/src/components/Tooltip/index.js#L192
https://github.com/Expensify/App/blob/1527fdcf443713bb058e6e76504006d74f6b1aa8/src/components/ContextMenuItem.js#L77
<Tooltip text={text} resetsOnClickOutside={false}>