-
Notifications
You must be signed in to change notification settings - Fork 7
Use popover
with Tooltip
#307
Conversation
🦋 Changeset detectedLatest commit: 4554cf0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
ba46889
to
85272af
Compare
@state() | ||
private effectivePlacement: Placement = this.placement ?? 'bottom'; | ||
|
||
#arrowElementRef = createRef<HTMLDivElement>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTMLDivElement
and HTMLSpanElement
don't give us any special properties—and they make markup changes prone to unnecessary typechecking failures. I can't see a good use for them. Anyone else feel the same?
85272af
to
9b34405
Compare
src/tooltip.ts
Outdated
strategy: 'fixed', | ||
middleware: [ | ||
offset(6), | ||
offset(4), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From Design.
src/tooltip.ts
Outdated
shift(), | ||
arrow({ element: arrowElement }), | ||
shift({ | ||
limiter: limitShift({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bcf6370
to
349d66e
Compare
349d66e
to
3721c4c
Compare
} | ||
:host { | ||
display: inline-block; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah!
top: arrowY === null ? '' : `${arrowY}px`, | ||
right: '', | ||
bottom: '', | ||
[staticSide]: '-3px', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
staticSide
is no longer needed now that we're using an exact-size SVG instead of a box, which needed to be offset by half its height.
19ee16c
to
cb77a42
Compare
src/tooltip.ts
Outdated
} | ||
|
||
#hide() { | ||
this.#cleanUpFloatingUi?.(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue goes away if I switch #hide
to private hide
. Not great. But it's something. I'd leave a comment linking this comment.
I'll keep looking for a better solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also does the trick:
if (this.#cleanUpFloatingUi) {
this.#cleanUpFloatingUi();
}
Very silly. I'll push the above with a comment before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If no one else has any ideas, I can pull this branch down tomorrow AM and give it a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries. I suspect it's just an optional chaining bug deep in the bowels of Istanbul or wherever.
c67d9fb
to
80f8a7b
Compare
data-test="arrow" | ||
${ref(this.#arrowElementRef)} | ||
> | ||
${choose(this.effectivePlacement, [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
choose
is a thing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fancy!
80f8a7b
to
1f87efe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! This is great.
I noticed one small bug with the private-label stuff I think:
Screen.Recording.2024-08-15.at.1.56.06.PM.mov
export default [ | ||
css` | ||
@keyframes animate-tooltip { | ||
@keyframes tooltip { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dig dropping the animate-
prefix for keyframes 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. I figured "animate" is implied—both here and when it's use with animation
.
} | ||
:host { | ||
display: inline-block; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah!
A simple "transform" could replace Floating UI for the arrow if not for a Chrome | ||
bug with "popover" when "scale()" is animated on the popover or a container within | ||
it. With "transform" on the arrow, the arrow is initially offset by a couple pixels | ||
before landing in the correct position when the animation finishes. It only happens | ||
when the tooltip is left or right of its target. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very annoying, thanks for the comments here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100%. What a pain this was.
--arrow-height: 0.375rem; | ||
--arrow-width: 0.625rem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to duplicate these values in two spots or did you find value in bringing these up the chain to variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally used them in quite a few more places. But the only places they're used now are co-located. So I'll go ahead and duplicate them instead.
data-test="arrow" | ||
${ref(this.#arrowElementRef)} | ||
> | ||
${choose(this.effectivePlacement, [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fancy!
src/tooltip.ts
Outdated
} | ||
|
||
#hide() { | ||
this.#cleanUpFloatingUi?.(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If no one else has any ideas, I can pull this branch down tomorrow AM and give it a look
Awesome find! Looking into it now. |
import { createRef, ref } from 'lit/directives/ref.js'; | ||
import { customElement, property, state } from 'lit/decorators.js'; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
import { offsetParent } from 'composed-offset-position'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to remove the composed-offset-position
dependency from package.json now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do. Nice catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed one small bug with the private-label stuff I think:
@ynotdraw: Easy enough to fix. But this test should have caught it.
It didn't because I didn't add a await aTimeout(0)
to it to await Floating UI—to give Tooltip a chance to become visible. And, of course, aTimeout
doesn't work when timers are fake.
So I had work the timer stuff. I noticed a couple other tests were falsely passing and reworked those too. Instead of using fake timers, I gave the tests a way to override Tooltip's open and close delays.
I don't love the solution but couldn't find better way. More on why I went with data attributes here. Let me know what you think, all considered, or if you have other ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, also swapped out ARIA attribute selectors for data attribute selectors after coming across this, which I think I added.
Perhaps an example of why we should always use data attribute selectors in tests despite ARIA attribute selectors being in vogue because of Testing Library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work going through all of that! What you have here makes sense to me 👍
Perhaps an example of why we should always use data attribute selectors in tests despite ARIA attribute selectors being in vogue because of Testing Library.
Definitely. If I've got some time tomorrow I can write some thoughts up for CONTRIBUTING.md and update any remaining stragglers in the codebase if we'd like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. I've got a note too. I'll get to it if you don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 popover
is so amazing!
// The open and close delays are stored in data attributes so tests can | ||
// configure them. Tests configure them, rather than using fake timers, | ||
// because they need real timers so they can await Floating UI's setup. | ||
// | ||
// Conditionals here and in `#scheduleClose` based on `navigator.webdriver` | ||
// would be a lot nicer. But the non-`navigator.webdriver` condition would | ||
// never get hit in tests, so we'd fail to meet our coverage thresholds. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other nice thing about these is that they're still private to the component due to the closed shadow root, so consumers have no way to adjust them (other than going through design and talking to us!). You love to see it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, yeah. CSS variables would work here too. But, of course, they have the drawback of being public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work going through all of that! What you have here makes sense to me 👍
Perhaps an example of why we should always use data attribute selectors in tests despite ARIA attribute selectors being in vogue because of Testing Library.
Definitely. If I've got some time tomorrow I can write some thoughts up for CONTRIBUTING.md and update any remaining stragglers in the codebase if we'd like.
No kidding. Many problems would be unfixable without it. I'm just going to throw |
🚀 Description
setContainingBlock
. It also fixed a couple outstanding bugs where Tooltip wasn't escaping its container.📋 Checklist
🔬 How to Test
@mayuri-todkar tested this against a few applications (🙏). However, if you want to test a reproduction:
📸 Images/Videos of Functionality
Before
After